home *** CD-ROM | disk | FTP | other *** search
/ Saar AMOK 2 / Saar AMOK II - Oktober 1994 (1994)(Kreativ Marketing)(DE)[!][I-7598].iso / disks / 651_700 / 698 / csh / csh537src.lha / comm1.c next >
C/C++ Source or Header  |  1994-03-11  |  58KB  |  2,565 lines

  1. /*
  2.  * COMM1.C
  3.  *
  4.  * Matthew Dillon, August 1986
  5.  *
  6.  * Version 2.07M by Steve Drew 10-Sep-87
  7.  * Version 4.01A by Carlo Borreo & Cesare Dieni 17-Feb-90
  8.  * Version 5.00L by Urban Mueller 17-Feb-91
  9.  * Version 5.20L by Andreas M. Kirchwitz (Fri, 13 Mar 1992)
  10.  *
  11.  */
  12.  
  13. #include "shell.h"
  14.  
  15. /* comm1.c */
  16. static void display_file(char *filestr);
  17. static int search_file( long mask, char *s, char *fullpath );
  18. static int rm_file    ( long mask, char *s, char *fullpath );
  19. static int quicksearch(char *name, int nocasedep, char *pattern);
  20. static void setsystemtime(struct DateStamp *ds);
  21. static int found( char *lstart, int lnum, int loffs, char *name, char left );
  22.  
  23. void lformat( char *s, char *d, FILEINFO *info );
  24.  
  25. extern int has_wild;
  26.  
  27. int
  28. do_sleep( void )
  29. {
  30.     int i;
  31.  
  32.     if (ac == 2) for (i=atoi(av[1]); i>0 && !CHECKBREAK(); i--) Delay(50);
  33.     return 0;
  34. }
  35.  
  36. #if 0
  37. /* AMK: if you change this, you must change do_chmod() also!! */
  38. int
  39. do_protect( void )
  40. {
  41.     static char flags[]="DEWRAPSH";
  42.     char *s, *p;
  43.     long setmask=0, clrmask=0xFF, mask;
  44.     int  i, mode=0, stat;
  45.     DPTR *dp;
  46.  
  47.     for (s=strupr(av[--ac]); *s; s++) {
  48.         if (*s=='=') { mode=0; continue; }
  49.         if (*s=='+') { mode=1; clrmask=FIBF_ARCHIVE; continue; }
  50.         if (*s=='-') { mode=2; clrmask=FIBF_ARCHIVE; continue; }
  51.  
  52.         if (*s=='X') *s='E';
  53.         if (p=index(flags, *s)) {
  54.             if( mode==0 ) setmask|= 1<<(p-flags), clrmask=0xFF;
  55.             if( mode==1 ) setmask|= 1<<(p-flags);
  56.             if( mode==2 ) clrmask|= 1<<(p-flags);
  57.         } else {
  58.             ierror(av[ac],500);
  59.             return 20;
  60.         }
  61.     }
  62.  
  63.     for (i=1; i<ac; i++) {
  64.         if( (dp=dopen(av[i],&stat))) {
  65.             mask = dp->fib->fib_Protection ^ 0x0F;
  66.             mask&=~clrmask;
  67.             mask|= setmask;
  68.             dclose(dp);
  69.             if( !SetProtection( av[i], mask ^ 0x0F))
  70.                 pError(av[i]);
  71.         } else
  72.             pError(av[i]);
  73.     }
  74.     return 0;
  75. }
  76. #endif
  77.  
  78. /* AMK: same as do_protect, but flags now as first argument */
  79. #if 0
  80. int
  81. do_chmod( void )
  82. {
  83.     static char flags[]="DEWRAPSH";
  84.     char *s, *p;
  85.     long setmask=0, clrmask=0xFF, mask;
  86.     int  i, mode=0, stat;
  87.     DPTR *dp;
  88.  
  89.     for (s=strupr(av[1]); *s; s++) {       /* AMK: changed */
  90.         if (*s=='=') { mode=0; continue; }
  91.         if (*s=='+') { mode=1; clrmask=FIBF_ARCHIVE; continue; }
  92.         if (*s=='-') { mode=2; clrmask=FIBF_ARCHIVE; continue; }
  93.  
  94.         if (*s=='X') *s='E';
  95.         if (p=index(flags, *s)) {
  96.             if( mode==0 ) setmask|= 1<<(p-flags), clrmask=0xFF;
  97.             if( mode==1 ) setmask|= 1<<(p-flags);
  98.             if( mode==2 ) clrmask|= 1<<(p-flags);
  99.         } else {
  100.             ierror(av[1],500);     /* AMK: changed */
  101.             return 20;
  102.         }
  103.     }
  104.  
  105.     for (i=2; i<ac; i++) {                 /* AMK: changed */
  106.         if( (dp=dopen(av[i],&stat))) {
  107.             mask = dp->fib->fib_Protection ^ 0x0F;
  108.             mask&=~clrmask;
  109.             mask|= setmask;
  110.             dclose(dp);
  111.             if( !SetProtection( av[i], mask ^ 0x0F))
  112.                 pError(av[i]);
  113.         } else
  114.             pError(av[i]);
  115.     }
  116.     return 0;
  117. }
  118. #endif
  119.  
  120. #define FIBB_HOLD 7
  121. #define FIBF_HOLD (1<<FIBB_HOLD)
  122.  
  123. int do_chmod_internal(long arg_begin,long arg_end,long arg_flags)
  124. {
  125.     char *s;
  126.     LONG mask;
  127.     int  i, stat;
  128.     DPTR *dp;
  129.     BOOL do_user=FALSE,do_group=FALSE,do_other=FALSE,do_default=TRUE;
  130.     BOOL do_incl=FALSE,do_excl=FALSE,do_set=TRUE;
  131.  
  132.     /*strlwr(av[1]);*/
  133.  
  134.     for (i=arg_begin; i<arg_end; i++) {  /* all arguments except 'arg_flags' */
  135.  
  136.         if( (dp=dopen(av[i],&stat))) {
  137.             mask = dp->fib->fib_Protection;
  138.             dclose(dp);
  139.  
  140.             s = av[arg_flags];
  141.  
  142.             if (strchr(s,'+') || strchr(s,'-') || strchr(s,'=')) {
  143.  
  144.                 while (*s && !strchr("+-=",*s)) {
  145.                     switch (*s) {
  146.                     case 'u': do_user  = TRUE; break;
  147.                     case 'g': do_group = TRUE; break;
  148.                     case 'o': do_other = TRUE; break;
  149.                     case 'a': do_user  =
  150.                               do_group = 
  151.                               do_other = TRUE; break;
  152.                     default : ierror(av[1],500); return 20;
  153.                     }
  154.                     do_default = FALSE;
  155.                     ++s;
  156.                 }
  157.  
  158.                 do_set = FALSE;
  159.  
  160.                 switch (*s) {
  161.                 case '+': do_incl = TRUE; break;
  162.                 case '-': do_excl = TRUE; break;
  163.                 case '=': do_set  = TRUE; break;
  164.                 default : ierror(av[1],500); return 20;
  165.                 }
  166.  
  167.                 ++s;
  168.  
  169.             }
  170.  
  171.             if (do_default) {
  172.                 do_user=TRUE;
  173.             }
  174.  
  175.             if (do_set) {
  176.                 do_incl = TRUE;
  177.                 mask = FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE;
  178.             }
  179.  
  180.             mask &= (~FIBF_ARCHIVE);
  181.  
  182.             while (*s) {
  183.                 switch (*s) {
  184.                 case 'r' :
  185.                            if (do_incl) {
  186.                              if (do_user)  mask &= (~FIBF_READ);
  187.                              if (do_group) mask |= FIBF_GRP_READ;
  188.                              if (do_other) mask |= FIBF_OTR_READ;
  189.                            }
  190.                            else {
  191.                              if (do_user)  mask |= FIBF_READ;
  192.                              if (do_group) mask &= (~FIBF_GRP_READ);
  193.                              if (do_other) mask &= (~FIBF_OTR_READ);
  194.                            }
  195.                            break;
  196.                 case 'w' :
  197.                            if (do_incl) {
  198.                              if (do_user)  mask &= (~FIBF_WRITE);
  199.                              if (do_group) mask |= FIBF_GRP_WRITE;
  200.                              if (do_other) mask |= FIBF_OTR_WRITE;
  201.                            }
  202.                            else {
  203.                              if (do_user)  mask |= FIBF_WRITE;
  204.                              if (do_group) mask &= (~FIBF_GRP_WRITE);
  205.                              if (do_other) mask &= (~FIBF_OTR_WRITE);
  206.                            }
  207.                            break;
  208.                 case 'e' :
  209.                 case 'x' :
  210.                            if (do_incl) {
  211.                              if (do_user)  mask &= (~FIBF_EXECUTE);
  212.                              if (do_group) mask |= FIBF_GRP_EXECUTE;
  213.                              if (do_other) mask |= FIBF_OTR_EXECUTE;
  214.                            }
  215.                            else {
  216.                              if (do_user)  mask |= FIBF_EXECUTE;
  217.                              if (do_group) mask &= (~FIBF_GRP_EXECUTE);
  218.                              if (do_other) mask &= (~FIBF_OTR_EXECUTE);
  219.                            }
  220.                            break;
  221.                 case 'd' :
  222.                            if (do_incl) {
  223.                              if (do_user)  mask &= (~FIBF_DELETE);
  224.                              if (do_group) mask |= FIBF_GRP_DELETE;
  225.                              if (do_other) mask |= FIBF_OTR_DELETE;
  226.                            }
  227.                            else {
  228.                              if (do_user)  mask |= FIBF_DELETE;
  229.                              if (do_group) mask &= (~FIBF_GRP_DELETE);
  230.                              if (do_other) mask &= (~FIBF_OTR_DELETE);
  231.                            }
  232.                            break;
  233.                 case 'a' :
  234.                            if (do_incl)
  235.                              mask |= FIBF_ARCHIVE;
  236.                            else
  237.                              mask &= (~FIBF_ARCHIVE);
  238.                            break;
  239.                 case 'p' :
  240.                            if (do_incl)
  241.                              mask |= FIBF_PURE;
  242.                            else
  243.                              mask &= (~FIBF_PURE);
  244.                            break;
  245.                 case 's' :
  246.                            if (do_incl)
  247.                              mask |= FIBF_SCRIPT;
  248.                            else
  249.                              mask &= (~FIBF_SCRIPT);
  250.                            break;
  251.                 case 'h' :
  252.                            if (do_incl)
  253.                              mask |= FIBF_HOLD;
  254.                            else
  255.                              mask &= (~FIBF_HOLD);
  256.                            break;
  257.                 default  :
  258.                            ierror(av[1],500);
  259.                            return 20;
  260.                 }
  261.                 ++s;
  262.             }
  263.  
  264.             if( !SetProtection( av[i], mask ))
  265.                 pError(av[i]);
  266.         }
  267.         else
  268.             pError(av[i]);
  269.     }
  270.  
  271.     return 0;
  272. }
  273.  
  274. int do_protect(void)
  275. {
  276.     return do_chmod_internal(1,ac-1,ac-1);
  277. }
  278.  
  279. int do_chmod(void)
  280. {
  281.     return do_chmod_internal(2,ac,1);
  282. }
  283.  
  284.  
  285.  
  286. int do_chown(void)
  287. {
  288.     LONG mask;  /* 2x UWORD */
  289.     UWORD new_id;
  290.     int  i, stat;
  291.     DPTR *dp;
  292.  
  293.     new_id = myatoi(av[1],0,65535);
  294.     if (atoierr) {
  295.         fprintf(stderr,"UID/GID is a 16-bit wide UWORD (0-65535) !\n");
  296.         return 20;
  297.     }
  298.  
  299.     for (i=2; i<ac; i++) {  /* all arguments except first */
  300.  
  301.         if( (dp=dopen(av[i],&stat))) {
  302.             /*printf("%s, gid %d, uid %d\n",av[i],dp->fib->fib_OwnerGID,dp->fib->fib_OwnerUID);*/
  303.             mask = dp->fib->fib_OwnerGID + (new_id<<16);
  304.             dclose(dp);
  305.  
  306.             /*printf("  new mask: %ld\n",mask);*/
  307.             if (DOSBase->dl_lib.lib_Version<39) {
  308.                 if( !SetOwner37( av[i], mask ))
  309.                     pError(av[i]);
  310.             }
  311.             else {
  312.                 if( !SetOwner( av[i], mask ))
  313.                     pError(av[i]);
  314.             }
  315.         }
  316.         else
  317.             pError(av[i]);
  318.     }
  319.  
  320.     return 0;
  321. }
  322.  
  323.  
  324.  
  325. int do_chgrp(void)
  326. {
  327.     LONG mask;  /* 2x UWORD */
  328.     UWORD new_id;
  329.     int  i, stat;
  330.     DPTR *dp;
  331.  
  332.     new_id = myatoi(av[1],0,65535);
  333.     if (atoierr) {
  334.         fprintf(stderr,"UID/GID is a 16-bit wide UWORD (0-65535) !\n");
  335.         return 20;
  336.     }
  337.  
  338.     for (i=2; i<ac; i++) {  /* all arguments except first */
  339.  
  340.         if( (dp=dopen(av[i],&stat))) {
  341.             /*printf("%s, gid %d, uid %d\n",av[i],dp->fib->fib_OwnerGID,dp->fib->fib_OwnerUID);*/
  342.             mask = (dp->fib->fib_OwnerUID<<16) + new_id;
  343.             dclose(dp);
  344.  
  345.             /*printf("  new mask: %ld\n",mask);*/
  346.             if (DOSBase->dl_lib.lib_Version<39) {
  347.                 if( !SetOwner37( av[i], mask ))
  348.                     pError(av[i]);
  349.             }
  350.             else {
  351.                 if( !SetOwner( av[i], mask ))
  352.                     pError(av[i]);
  353.             }
  354.         }
  355.         else
  356.             pError(av[i]);
  357.     }
  358.  
  359.     return 0;
  360. }
  361.  
  362.  
  363.  
  364. int
  365. do_filenote( void )
  366. {
  367.     DPTR *dp;
  368.     char *note;
  369.     int i, stat;
  370.  
  371.     if( options&1 ) {
  372.         for( i=1; i<ac && !dobreak(); i++ )
  373.             if( dp=dopen( av[i], &stat )) {
  374.                 printf( "%-12s %s\n", av[i],dp->fib->fib_Comment );
  375.                 dclose( dp );
  376.             }
  377.     } else {
  378.         note=av[--ac];
  379.         for (i=1; i<ac; i++) if (!SetComment(av[i], note)) pError(av[i]);
  380.     }
  381.     return 0;
  382. }
  383.  
  384. int
  385. do_cat( void )
  386. {
  387.     FILE *fi;
  388.     int lctr, i, docr=0;
  389.     char buf[256], *l;
  390.  
  391.     prepscroll(0);
  392.     if (ac<=1) {
  393.         if (has_wild) { printf("No files matching\n"); return 20; }
  394.         lctr=0;
  395.         while (fgets(buf,256,stdin) && !dobreak()) {
  396.             if (options) printf("%4d ",++lctr);
  397.             quickscroll();
  398.             l=buf+strlen( buf )-1; docr=1;
  399.             if( l>=buf && *l=='\n' ) docr=0;
  400.             fputs(buf,stdout);
  401.         }
  402.     } else {
  403.         for (i=1; i<ac; i++)
  404.             if (fi = fopen (av[i], "r")) {
  405.                 lctr=0;
  406.                 while (fgets(buf,256,fi) && !dobreak()) {
  407.                     if (options&1) printf("%4d ",++lctr);
  408.                     quickscroll();
  409.                     l=buf+strlen( buf )-1; docr=1;
  410.                     if( l>=buf && *l=='\n' ) docr=0;
  411.                     fputs(buf,stdout); fflush(stdout);
  412.                 }
  413.                 fclose (fi);
  414.             } else
  415.                 pError(av[i]);
  416.     }
  417.     if( docr && isconsole(Output()))
  418.         putchar('\n');
  419.     return 0;
  420. }
  421.  
  422.  
  423.  
  424. char *add_simple_device(char *list,char *dev)
  425. {
  426.     char *new = NULL;
  427.  
  428.     if (list) {
  429.         if (new = malloc(strlen(dev)+strlen(list)+2)) {        /* null byte + \n */
  430.             strcpy(new,list);
  431.             strcat(new,dev);
  432.             strcat(new,"\n");
  433.             free(list);
  434.         }
  435.         else
  436.             new = list;
  437.     }
  438.     else {
  439.         if (new = malloc(strlen(dev)+2)) {            /* null byte + \n */
  440.             strcpy(new,dev);
  441.             strcat(new,"\n");
  442.         }
  443.     }
  444.  
  445.     return(new);
  446. }
  447.  
  448.  
  449.  
  450. void
  451. get_drives(char *buf)
  452. {
  453.     struct DosList *dl;
  454.     ULONG flags = LDF_DEVICES|LDF_READ;
  455.     char devname[256];
  456.     char **dev_list=NULL;
  457.     long i,dev_num=0;
  458.  
  459.     buf[0]=0;
  460.     if (dl=LockDosList(flags)) {
  461.         while (dl=NextDosEntry(dl,flags)) {
  462.             if (dl->dol_Task) {
  463.                 BtoCStr(devname,dl->dol_Name,254L);  /* 256 - '\0' + ':' */
  464.                 strcat(devname,":");
  465.                 add_array_list(&dev_list,&dev_num,devname);
  466.             }
  467.         }
  468.         UnLockDosList(flags);
  469.     }
  470.  
  471.     QuickSort(dev_list,dev_num);
  472.  
  473.     for(i=0; i<dev_num; i++) {
  474.         if (IsFileSystem(dev_list[i])) {
  475.             if (buf[0])
  476.                 strcat(buf,"\240");
  477.             strcat(buf,dev_list[i]);
  478.         }
  479.     }
  480.  
  481.     free_array_list(dev_list,dev_num);
  482. }
  483.  
  484. static char infobuf[100];
  485. static char namebuf[32];  /* AMK: old size was 12, too small for drive names */
  486.  
  487.  
  488. /* AMK: find last occurence of a character in a string */
  489. char *strlast(char *s,char c)
  490. {
  491.   char *p=NULL;
  492.   while(*s) {
  493.     if(*s==c)
  494.       p=s;
  495.     s++;
  496.   }
  497.   return(p);
  498. }
  499.  
  500.  
  501. char *
  502. drive_name( char *name )
  503. {
  504.     struct DosList *dl;
  505.     struct MsgPort *proc= (struct MsgPort *)DeviceProc( (void*)name );
  506.     ULONG flags = LDF_DEVICES|LDF_READ;
  507.     char devname[256];
  508.     char **dev_list=NULL;
  509.     long i,dev_num=0;
  510.  
  511.     /* AMK: we want no self-modifying code */
  512.     strncpy( namebuf, name, 31 );   /* AMK: 30 chars device name + ':' */
  513.     namebuf[31] = '\0';             /* AMK: null-terminated */
  514.     if (dl=LockDosList(flags)) {
  515.         while (dl=NextDosEntry(dl,flags)) {
  516.             if (dl->dol_Task) {
  517.                 BtoCStr(devname,dl->dol_Name,254L);  /* 256 - '\0' + ':' */
  518.                 strcat(devname,":");
  519.                 add_array_list(&dev_list,&dev_num,devname);
  520.             }
  521.         }
  522.         UnLockDosList(flags);
  523.     }
  524.  
  525.     QuickSort(dev_list,dev_num);
  526.  
  527.     for(i=0; i<dev_num; i++) {
  528.         if (IsFileSystem(dev_list[i])) {
  529.             if ((struct MsgPort *)DeviceProc(dev_list[i])==proc)
  530.                 strcpy(namebuf,dev_list[i]);
  531.         }
  532.     }
  533.  
  534.     free_array_list(dev_list,dev_num);
  535.  
  536.     return namebuf;
  537. }
  538.  
  539. int
  540. do_info( void )
  541. {
  542.     struct DosList *dl;
  543.     ULONG flags = LDF_DEVICES|LDF_READ;
  544.     char devname[256];
  545.     char **dev_list=NULL;
  546.     long i,dev_num=0;
  547.  
  548.     if (options&2)
  549.         puts("Unit     Size  Block  Type   Used   Free Full Errs  Status    Name");
  550.     else
  551.         puts("Unit     Size  Bytes  Used Blk/Byte-Free Full Errs  Status    Name");
  552.  
  553.     if( ac==1 ) {
  554.         if (dl=LockDosList(flags)) {
  555.             while (dl=NextDosEntry(dl,flags)) {
  556.                 if (dl->dol_Task) {
  557.                     BtoCStr(devname,dl->dol_Name,254L);  /* 256 - '\0' + ':' */
  558.                     strcat(devname,":");
  559.                     add_array_list(&dev_list,&dev_num,devname);
  560.                 }
  561.             }
  562.             UnLockDosList(flags);
  563.         }
  564.  
  565.         QuickSort(dev_list,dev_num);
  566.  
  567.         for(i=0; !dobreak() && i<dev_num; i++) {
  568.             if (IsFileSystem(dev_list[i])) {
  569.                 oneinfo(dev_list[i],0);
  570.             }
  571.         }
  572.  
  573.         free_array_list(dev_list,dev_num);
  574.     }
  575.     else {
  576.         for( i=1; i<ac; i++ )
  577.             oneinfo( drive_name( av[i] ), 0 );
  578.     }
  579.  
  580.     return 0;
  581. }
  582.  
  583.  
  584.  
  585. /* these defines are new in OS 3.x */
  586. #ifndef ID_FASTDIR_DOS_DISK
  587. #define ID_FASTDIR_DOS_DISK (0x444F5304L)
  588. #endif
  589. #ifndef ID_FASTDIR_FFS_DISK
  590. #define ID_FASTDIR_FFS_DISK (0x444F5305L)
  591. #endif
  592.  
  593.  
  594.  
  595. /* AMK: new mode==6 to suppress output if disk is not present */
  596. char *
  597. oneinfo( char *name, int mode )
  598. {
  599.     struct InfoData *info;
  600.     struct DevProc *devproc;
  601.     struct DeviceList *dl;
  602.     BPTR lock;
  603.     long size, free, freebl, blocks;
  604.     char buf[130], *state, *type;
  605.     char *fmt="%s\240%s\240%d\240%d\240%d\240%s\240%d%%\240%d\240%s\240%s";
  606.  
  607.     Myprocess->pr_WindowPtr = (APTR)(-1);
  608.  
  609.     if (!name) name="";
  610.  
  611.     if (mode<=1 || mode>=5)
  612.         strcpy(infobuf,"");
  613.     else
  614.         strcpy(infobuf,"0");
  615.  
  616.     info=(struct InfoData *)SAllocMem(sizeof(struct InfoData),MEMF_PUBLIC|MEMF_CLEAR);
  617.  
  618.     if (devproc=GetDeviceProc(name,NULL)) {
  619.         if (DoPkt(devproc->dvp_Port,ACTION_DISK_INFO,MKBADDR(info),NULL,NULL,NULL,NULL)==DOSTRUE) {
  620.             BOOL go_on = FALSE;
  621.             char *spclfmt;
  622. #if 0
  623.             if (!NameFromLock(lock, buf, 128L)) {
  624.                 fprintf(stderr,"csh.oneinfo: NameFromLock() failed\n");
  625.                 strcpy(buf,name);
  626.             }
  627.             if (p=strlast(buf,':')) *p = '\0';
  628.             /* AMK: we want the last occurence of ':', not the first;
  629.                     ':' and '/' are legal path name components !!
  630.             if (p=index(buf,':')) *p = '\0';
  631.             */
  632. #endif
  633.             switch (mode) {
  634.                 case 0:
  635.                     if (options&1)
  636.                         spclfmt = "";
  637.                     else
  638.                         spclfmt = "%-7s %s\n";
  639.                     break;
  640.                 case 1:
  641.                     spclfmt = "%s\240%s\n";
  642.                     break;
  643.                 case 2:
  644.                 case 3:
  645.                 case 4:
  646.                     spclfmt = "0";
  647.                     break;
  648.                 case 5:
  649.                     spclfmt = "";
  650.                     break;
  651.                 default:
  652.                     spclfmt = "";
  653.                     break;
  654.             }
  655.  
  656.             switch (info->id_DiskType) {
  657.                 case ID_UNREADABLE_DISK:
  658.                     sprintf(infobuf,spclfmt,name,"Unreadable disk");
  659.                     break;
  660.                 case ID_NOT_REALLY_DOS:
  661.                     sprintf(infobuf,spclfmt,name,"Not a DOS disk");
  662.                     break;
  663.                 case ID_KICKSTART_DISK:
  664.                     sprintf(infobuf,spclfmt,name,"Kickstart disk");
  665.                     break;
  666.                 case (0x42555359L):  /* 'BUSY' */
  667.                     sprintf(infobuf,spclfmt,name,"Disk is busy");
  668.                     break;
  669.                 case ID_NO_DISK_PRESENT:
  670.                     sprintf(infobuf,spclfmt,name,"No disk present");
  671.                     break;
  672.                 default:
  673.                     sprintf(infobuf,spclfmt,name,"Unknown disk type");
  674.                     go_on = TRUE;
  675.                     break;
  676.             }
  677.  
  678.             if (go_on && (lock=Lock(name,ACCESS_READ))) {
  679.                 UnLock(lock);
  680.                 /* note:  we call Lock() to be sure that the volume is readable */
  681.  
  682.                 switch(info->id_DiskType) {
  683.                     case ID_MSDOS_DISK:       type=" MSDOS"; break;
  684.                     case ID_DOS_DISK:         type="   OFS"; break;
  685.                     case ID_FFS_DISK:         type="   FFS"; break;
  686.                     case ID_INTER_DOS_DISK:   type="IN/OFS"; break;
  687.                     case ID_INTER_FFS_DISK:   type="  INTL"; break;
  688.                     case ID_FASTDIR_DOS_DISK: type="DC/OFS"; break;
  689.                     case ID_FASTDIR_FFS_DISK: type="  DCFS"; break;
  690.                     default:                  type="   n/a"; break;
  691.                 }
  692.  
  693.                 strcpy(buf,"n/a");
  694.                 if (dl = (struct DeviceList *)BADDR(info->id_VolumeNode))
  695.                     BtoCStr(buf,dl->dl_Name,100L);
  696.  
  697.                 switch(info->id_DiskState) {
  698.                     case ID_WRITE_PROTECTED: state="Read Only "; break;
  699.                     case ID_VALIDATED:       state="Read/Write"; break;
  700.                     case ID_VALIDATING:      state="Validating"; break;
  701.                     default:                 state="Unknown   "; break;
  702.                 }
  703.  
  704. #if 0
  705.                 size   = (info->id_NumBlocks + 2) * info->id_BytesPerBlock;
  706. #endif
  707.                 size   = info->id_NumBlocks * info->id_BytesPerBlock;
  708.                 freebl = info->id_NumBlocks - info->id_NumBlocksUsed;
  709.                 free   = freebl * info->id_BytesPerBlock;
  710.                 blocks = info->id_NumBlocks;
  711. #if 0
  712.                 printf("percents: %s... %ld, %ld, %ld, %ld, %ld\n",name,
  713.                     ((info->id_NumBlocksUsed+2) * 100)/blocks,
  714.                     (info->id_NumBlocksUsed * 100)/(blocks+2),
  715.                     (((info->id_NumBlocksUsed * 1000)/blocks)+5)/10,
  716.                     ((((info->id_NumBlocksUsed+2) * 1000)/blocks)+5)/10,
  717.                     (((info->id_NumBlocksUsed * 1000)/(blocks+2))+5)/10
  718.                 );
  719. #endif
  720.  
  721.                 if (mode==0 && options&2) {
  722.                     fmt="%-7s%6s%6d %6s %6s %6s %3d%%%4d  %10s %s\n";
  723.                     sprintf(infobuf,fmt,
  724.                         name,
  725.                         itok( size ),
  726.                         info->id_BytesPerBlock,
  727.                         type,
  728.                         itok( info->id_NumBlocksUsed*info->id_BytesPerBlock ),
  729.                         itok( free ),
  730.                         (blocks) ? (int)((( (double)info->id_NumBlocksUsed/(double)blocks ) * 1000.0 + 5.0) / 10.0) : 0,
  731. #if 0
  732.                         (blocks) ? ((info->id_NumBlocksUsed * 1000)/blocks + 5) / 10 : 0,
  733. #endif
  734.                         info->id_NumSoftErrors,
  735.                         state,
  736.                         buf);
  737.                 }
  738.                 else if (mode<=1) {
  739.                     if (mode==0) fmt="%-7s%6s%6d%7d%7d %6s%4d%%%4d  %s %s\n";
  740.                     sprintf(infobuf,fmt,
  741.                         name,
  742.                         itok( size ),
  743.                         info->id_BytesPerBlock,
  744.                         info->id_NumBlocksUsed,
  745.                         freebl,
  746.                         itok( free ),
  747.                         (blocks) ? (int)((( (double)info->id_NumBlocksUsed/(double)blocks ) * 1000.0 + 5.0) / 10.0) : 0,
  748.                         info->id_NumSoftErrors,
  749.                         state,
  750.                         buf);
  751.                 }
  752.                 else if (mode==2) sprintf(infobuf,"%d",free);
  753.                 else if (mode==3) sprintf(infobuf,"%d",freebl);
  754.                 else if (mode==4) sprintf(infobuf,"%s",itok(free));
  755.                 else if (mode==5) sprintf(infobuf,"%s:",buf);
  756.             }
  757.         }
  758.         else
  759.             pError(name);
  760.         FreeDeviceProc(devproc);
  761.     }
  762.  
  763. #if 0
  764.     else {
  765.         if (mode==1) {
  766.             struct MsgPort *devtask;
  767.             sprintf(infobuf,"%s\240No disk present\n",name);
  768.             if (devtask=(struct MsgPort *)DeviceProc(name)) {
  769.                 struct InfoData *infodata;
  770.                 infodata = SAllocMem(sizeof(struct InfoData),MEMF_PUBLIC|MEMF_CLEAR);
  771.                 if (DoPkt(devtask,ACTION_DISK_INFO,MKBADDR(infodata),NULL,NULL,NULL,NULL)) {
  772.                     switch (infodata->id_DiskType) {
  773.                     case ID_UNREADABLE_DISK:
  774.                         sprintf(infobuf,"%s\240Unreadable disk\n",name);
  775.                         break;
  776.                     case ID_NOT_REALLY_DOS:
  777.                         sprintf(infobuf,"%s\240Not a DOS disk\n",name);
  778.                         break;
  779.                     case ID_KICKSTART_DISK:
  780.                         sprintf(infobuf,"%s\240Kickstart disk\n",name);
  781.                         break;
  782.                     case (0x42555359L):  /* 'BUSY' */
  783.                         sprintf(infobuf,"%s\240Busy\n",name);
  784.                         break;
  785.                     case ID_NO_DISK_PRESENT:
  786.                     default:
  787.                         sprintf(infobuf,"%s\240No disk present\n",name);
  788.                         break;
  789.                     }
  790.                 }
  791.                 FreeMem(infodata,sizeof(struct InfoData));
  792.             }
  793.         }
  794.         else if (mode==0) {
  795.             if (options&1) {
  796.                 sprintf(infobuf,"");
  797.             }
  798.             else {
  799.                 struct MsgPort *devtask;
  800.                 sprintf(infobuf,"%-7s No disk present\n",name);
  801.                 if (devtask=(struct MsgPort *)DeviceProc(name)) {
  802.                     struct InfoData *infodata;
  803.                     infodata = SAllocMem(sizeof(struct InfoData),MEMF_PUBLIC|MEMF_CLEAR);
  804.                     if (DoPkt(devtask,ACTION_DISK_INFO,MKBADDR(infodata),NULL,NULL,NULL,NULL)) {
  805.                         switch (infodata->id_DiskType) {
  806.                         case ID_UNREADABLE_DISK:
  807.                             sprintf(infobuf,"%-7s Unreadable disk\n",name);
  808.                             break;
  809.                         case ID_NOT_REALLY_DOS:
  810.                             sprintf(infobuf,"%-7s Not a DOS disk\n",name);
  811.                             break;
  812.                         case ID_KICKSTART_DISK:
  813.                             sprintf(infobuf,"%-7s Kickstart disk\n",name);
  814.                             break;
  815.                         case (0x42555359L):  /* 'BUSY' */
  816.                             sprintf(infobuf,"%-7s Disk is busy\n",name);
  817.                             break;
  818.                             case ID_NO_DISK_PRESENT:
  819.                         default:
  820.                             sprintf(infobuf,"%-7s No disk present\n",name);
  821.                             break;
  822.                         }
  823.                     }
  824.                     FreeMem(infodata,sizeof(struct InfoData));
  825.                 }
  826.             }
  827.         }
  828.         else if (mode==5) sprintf(infobuf,"");
  829.         else              sprintf(infobuf,"0");
  830.     }
  831. #endif
  832.  
  833.     if (mode==0) printf("%s",infobuf);
  834.  
  835.     FreeMem(info,sizeof(struct InfoData));
  836.     Myprocess->pr_WindowPtr = o_noreq ? (APTR) -1L : Mywindow;
  837.  
  838.     return infobuf;
  839. }
  840.  
  841.  
  842. /* things shared with display_file */
  843.  
  844. #define DIR_SHORT 0x1
  845. #define DIR_FILES 0x2
  846. #define DIR_DIRS  0x4
  847. #define DIR_NOCOL 0x8
  848. #define DIR_NAMES 0x10
  849. #define DIR_HIDE  0x20
  850. #define DIR_LEN   0x40
  851. #define DIR_TIME  0x80
  852. #define DIR_BACK  0x100
  853. #define DIR_UNIQ  0x200
  854. #define DIR_IDENT 0x400
  855. #define DIR_CLASS 0x800
  856. #define DIR_QUIET 0x1000
  857. #define DIR_AGE   0x2000
  858. #define DIR_VIEW  0x4000
  859. #define DIR_NOTE  0x8000
  860. #define DIR_PATH  0x10000
  861. #define DIR_LFORM 0x20000
  862. #define DIR_BOT   0x40000
  863. #define DIR_TOP   0x80000
  864. #define DIR_LINK  0x100000
  865.  
  866. static char *lastpath = NULL;
  867. static int filecount, dircount, col, colw, wwidth;
  868. static long bytes, blocks;
  869.  
  870. /* the args passed to do_dir will never be expanded */
  871.  
  872. extern expand_err;
  873. extern int w_width;
  874.  
  875. static struct DateStamp Stamp;
  876. static char *LineBuf, *LinePos, LastWasDir, *LFormat, _LFormat[80], NoTitles;
  877.  
  878. int
  879. do_dir( void )
  880. {
  881.     int i=1, c, eac, reverse, nump=ac, retcode=0;
  882.     char **eav=NULL, **av1=NULL, **av2=NULL, inter=isconsole(Output());
  883.     char linebuf[1024];
  884.     char *fmtstr;
  885.     int (*func)(), ac1, ac2, factor=0;
  886.  
  887.     LineBuf=LinePos=linebuf;
  888.     LastWasDir=NoTitles=0;
  889.     colw=-1;
  890.  
  891.     LFormat=_LFormat;
  892.  
  893.     if( options&DIR_CLASS ) options|=DIR_IDENT;
  894.     if( !(options & (DIR_FILES | DIR_DIRS))) options|= DIR_FILES | DIR_DIRS;
  895.  
  896.     DateStamp( &Stamp );
  897.  
  898.     col = filecount = dircount = bytes = blocks = 0L;
  899.     if (lastpath) free(lastpath);
  900.     lastpath=NULL;
  901.  
  902.     wwidth=77;
  903.     if( inter )
  904.         wwidth=w_width;
  905.  
  906.     if( options&DIR_SHORT )
  907.         strcpy(LFormat," %-18n%19m");
  908.     else if( options&DIR_PATH )
  909.         strcpy(LFormat," %-50p %7s %d"), NoTitles=1;
  910.     else {
  911.         if ( options&DIR_NOTE )
  912.             strcpy(LFormat,"  %-30n %o");
  913.         else if ( options&DIR_LINK )
  914.             strcpy(LFormat,"  %-30n %L");
  915.         else {
  916. #if 1
  917.             strcpy(LFormat,"  ");
  918. #else
  919.             strcpy(LFormat,"  %-30n ");
  920. #endif
  921.             if( options&DIR_HIDE )
  922.                 strcat(LFormat, "%e");
  923.             strcat(LFormat,"%c%I%f ");
  924.             if( options&DIR_VIEW )
  925.                 strcat(LFormat,"%10v  ");
  926.             else
  927.                 strcat(LFormat,"%8s  ");
  928. #if 0
  929.             if( !(options&DIR_QUIET) )
  930.                 strcat(LFormat,options&DIR_VIEW?"%5b ":"%4b ");
  931. #endif
  932.             if( options&DIR_IDENT )
  933.                 strcat(LFormat,"%-10k");
  934.             else if( options&DIR_AGE )
  935.                 strcat(LFormat,"%a");
  936.             else
  937.                 strcat(LFormat,"%d %t");
  938. #if 1
  939.             strcat(LFormat,"  %N");
  940. #endif
  941.         }
  942.     }
  943.  
  944.     if ( fmtstr=get_var(LEVEL_SET,v_dirformat) ) {
  945.         strncpy(LFormat,fmtstr,79);    /* copy to _LFormat[80] */
  946.         LFormat[79]=0;
  947.     }
  948.  
  949.     if ( options&DIR_LFORM ) {
  950.         if (ac>1)
  951.             LFormat=av[i++];
  952.         else {
  953.             show_usage(NULL);
  954.             return 20;
  955.         }
  956.     }
  957.  
  958.     if( ac == i) ++nump, av[i]="";
  959.     if( options&DIR_UNIQ) {
  960.         if( ac-i!=2 )  { show_usage(NULL); return 20; }
  961.         i=0, nump=3;
  962.     }
  963.  
  964.     prepscroll(0);
  965.     for( ; i<nump && !CHECKBREAK(); ++i ) {
  966.         if( options&DIR_UNIQ ) {
  967.             switch( i ) {
  968.                 case 0: av1=expand( av[ac-2], &ac1 );
  969.                         av2=expand( av[ac-1], &ac2 );
  970.                         eav=without( av1, ac1, av2, ac2, &eac, 1 );
  971.                         break;
  972.                 case 1: printf("\nCommon files\n");
  973.                         eav=and( av1, ac1, av2, ac2, &eac, 1 );
  974.                         break;
  975.                 case 2: printf("\n");
  976.                         eav=without( av2, ac2, av1, ac1, &eac, 1 );
  977.                         break;
  978.             }
  979.             col = filecount = dircount = bytes = blocks = 0L;
  980.             if (lastpath) free(lastpath);
  981.             lastpath=NULL;
  982.  
  983.         /* AMK: enhanced handling of non-matching patterns */
  984.         } else if (!(eav = expand(av[i], &eac))) {
  985.             if (IoError) {
  986.                 ierror(av[i],IoError);
  987.                 retcode=5;
  988.             }
  989. #if 0
  990.             else {
  991.                 if (strlen(av[i])>0)
  992.                     fprintf(stderr,"%s: No match.\n",av[i]);
  993.             }
  994. #endif
  995.             continue;
  996.         }
  997.  
  998.         reverse= ( options&DIR_BACK ) ? 1 : 0;
  999.         func=cmp;
  1000.         if( options & DIR_TIME) func=datecmp_csh;
  1001.         if( options & DIR_LEN ) func=sizecmp;
  1002.         if( options & DIR_CLASS)func=classcmp;
  1003.         if( options & DIR_BOT ) factor=-99999999;
  1004.         if( options & DIR_TOP ) factor= 99999999;
  1005.         DirQuickSort(eav, eac, func, reverse, factor);
  1006.         for(c=0; c<eac && !CHECKBREAK(); ++c) {
  1007.             if( options & DIR_HIDE ) {
  1008.                 char *b=FilePart(eav[c]);
  1009.                 int  l=strlen(b)-5;
  1010.                 FILEINFO *info =(FILEINFO *)eav[c] - 1;
  1011.                 if(*b=='.'|| (l>=0 && !strcmp(b+l,".info"))||(info->flags&128))
  1012.                     continue;
  1013.             }
  1014.             if (options & DIR_NAMES) {
  1015.                 FILEINFO *info = (FILEINFO *)eav[c] - 1;
  1016.                 if(options&(info->size<0 ? DIR_DIRS: DIR_FILES))
  1017.                     puts(eav[c]);
  1018.             } else
  1019.                 display_file(eav[c]);
  1020.         }
  1021.  
  1022.         if (col) { quickscroll(); puts(LinePos=LineBuf); col=0; }
  1023.  
  1024.         if( LastWasDir )
  1025.             printf(o_lolite), LastWasDir=0;
  1026.  
  1027.         if (options&DIR_UNIQ || (filecount>1 && i==nump-1)) {
  1028.             blocks += filecount-dircount; /* account for dir blocks */
  1029.             quickscroll();
  1030.             printf(" %ld Blocks, %s Bytes used in %d files\n",
  1031.                 blocks, itoa(bytes), filecount);
  1032.         }
  1033.         if( options&DIR_UNIQ )
  1034.             free(eav);
  1035.         else
  1036.             free_expand (eav);
  1037.     }
  1038.     if (lastpath) free(lastpath);
  1039.     lastpath=NULL;
  1040.  
  1041.     if( options&DIR_UNIQ )
  1042.         free_expand( av1 ), free_expand( av2 );
  1043.  
  1044.     return retcode;
  1045. }
  1046.  
  1047. static int MultiCol=-1;
  1048.  
  1049. static char
  1050. pathcomp( char *s1, char *s2 )
  1051. {
  1052.     char ret, *t, c;
  1053.  
  1054.     t=FilePart( s2 ); c=*t; *t=0;
  1055.     ret=stricmp( s1, s2 );
  1056.     *t=c;
  1057.     return ret;
  1058. }
  1059.  
  1060. static void
  1061. display_file( char *filestr )
  1062. {
  1063.     /* struct InfoData *id=AllocMem( sizeof(struct InfoData), 0); */
  1064.     int isadir, len, collen;
  1065.     char sc, *base, buf[1024], *hilite;
  1066.     FILEINFO *info;
  1067.     BPTR thislock;
  1068.  
  1069.     base=FilePart(filestr);
  1070.     sc = *base;
  1071.     *base = 0;
  1072.     /* if (thislock==NULL) return; */
  1073.     if( !NoTitles ) {
  1074.         if( !lastpath || pathcomp( filestr, lastpath)) {
  1075.             if(!(thislock=Lock(filestr,SHARED_LOCK)))
  1076.                 return;
  1077.             if (col) { quickscroll(); puts(LinePos=LineBuf); col=0; }
  1078.             quickscroll();
  1079.             if (!NameFromLock(thislock, buf, 256)) {
  1080.                 fprintf(stderr,"csh.display_file: NameFromLock() failed\n");
  1081.                 strcpy(buf,filestr);
  1082.             }
  1083.             if( LastWasDir )
  1084.                 printf(o_lolite), LastWasDir=0;
  1085.             printf("Directory of %s\n", buf );
  1086.             /* Info( thislock, id ); */
  1087.             /* itok((id->id_NumBlocks-id->id_NumBlocksUsed)*id->id_BytesPerBlock));*/
  1088.             /* FreeMem( id, sizeof(struct InfoData)); */
  1089.             lastpath = salloc(256);
  1090.             strcpy(lastpath,filestr);
  1091.             /*lastpath=filestr;*/
  1092.             UnLock(thislock);
  1093.         }
  1094.     }
  1095.     *base    = sc;
  1096.  
  1097.     info   = (FILEINFO *)filestr - 1;
  1098.     isadir = info->size<0;
  1099.  
  1100.     if( !(options & (isadir ? DIR_DIRS : DIR_FILES)))
  1101.         return;
  1102.  
  1103.     hilite="";
  1104.     if (isadir!=LastWasDir && !(options & DIR_NOCOL))
  1105.         hilite=isadir ? o_hilite : o_lolite, LastWasDir=isadir;
  1106.  
  1107.     lformat(LFormat, buf, info);
  1108.  
  1109.     if( MultiCol==-1 ) {
  1110.         quickscroll();
  1111.         printf("%s%s",hilite,buf);
  1112.     } else {
  1113.         len=strlen(buf);
  1114.         if( col+len>wwidth ) {
  1115.             quickscroll();
  1116.             puts(LineBuf);
  1117.             LinePos=LineBuf; col=0;
  1118.         }
  1119.         if( MultiCol )
  1120.             colw=MultiCol;
  1121.         else if( colw==-1 )
  1122.             colw=len;
  1123.         collen= (len+colw-1)-(len+colw-1)%colw;
  1124.         col+=collen;
  1125.         LinePos+=sprintf(LinePos,"%s%-*s",hilite,collen,buf);
  1126.     }
  1127.  
  1128.     if(info->size>0)
  1129.         bytes  += info->size;
  1130.     blocks += info->blocks;
  1131.     filecount++;
  1132. }
  1133.  
  1134. static char linebuf[1024];
  1135. static long dlen, dblocks;
  1136.  
  1137. static int
  1138. count( long mask, char *s, char *path )
  1139. {
  1140.     FIB *fib=(FIB*)s-1;
  1141.     dlen+=fib->fib_Size;
  1142.     dblocks+=fib->fib_NumBlocks+1;
  1143.     return 0;
  1144. }
  1145.  
  1146.  
  1147. /* code contribution by Carsten Heyl, modified by AMK */
  1148. void ReadSoftLink(char *path, char *buf, int buflen)
  1149. {
  1150.     BPTR MyLock;
  1151.     BPTR DevLock;
  1152.     LONG Err, l;
  1153.     UBYTE *bs;
  1154.     struct MsgPort *port;
  1155.  
  1156.     if (buflen>9)
  1157.         strcpy(buf,"<unknown>");
  1158.     else
  1159.         buf[0] = '\0';    /* just terminate buffer. alternative ? */
  1160.  
  1161.     if ( (l=strlen(path)) > 254 )
  1162.         return;
  1163.  
  1164.     if (!(bs=AllocMem(256,MEMF_CLEAR|MEMF_PUBLIC)))
  1165.         return;
  1166.  
  1167.     bs[255] = '\0';
  1168.  
  1169.     /* build BCPL string */
  1170.     bs[0] = l;
  1171.     memcpy(&bs[1], path, l+1);
  1172.  
  1173.     /* GetDeviceProc or DeviceProc? */
  1174.     if (!(port = DeviceProc(path))) {
  1175.         FreeMem(bs,256);
  1176.         return;
  1177.     }
  1178.  
  1179.     DevLock = (BPTR)IoErr();
  1180.  
  1181.     MyLock = DoPkt(port,ACTION_LOCATE_OBJECT,DevLock,MKBADDR(bs),
  1182.                 ACCESS_READ,NULL,NULL);
  1183.     Err = IoErr();
  1184.  
  1185.     if (!MyLock && (Err==ERROR_IS_SOFT_LINK)) {
  1186. #if 0
  1187.         ReadLink(port,DevLock,(UBYTE *)path,(UBYTE *)buf,buflen);
  1188. #else
  1189.         DoPkt(port,ACTION_READ_LINK,DevLock,(LONG)path,(LONG)buf,buflen,NULL);
  1190. #endif
  1191.     }
  1192.  
  1193.     if (MyLock) UnLock(MyLock);
  1194.     FreeMem(bs,256);
  1195. }
  1196.  
  1197.  
  1198. void
  1199. lformat( char *s, char *d, FILEINFO *info )
  1200. {
  1201.     long mi=0;
  1202.     char buf[1024], *w, *t, *class;
  1203.     DPTR *dp;
  1204.     int stat, i, form, sign, cut, size=info->size;
  1205.     char *(*func)(int num);
  1206.  
  1207.     MultiCol=-1;
  1208.     while( *s ) {
  1209.         if( *s!='%' ) { *d++=*s++; continue; }
  1210.         sign=1; form=0; cut=0; s++;
  1211.         if( *s=='-' ) s++, sign=-1;
  1212.         if( *s=='.' ) s++, cut=1;
  1213.         while( *s>='0' && *s<='9' ) form=10*form+*s++-'0';
  1214.         w=buf; w[0]=0; w[1]=0;
  1215.         switch( *s ) {
  1216.         case 'p': strcpy(w,(char *)(info+1));             break;
  1217.         case 'b': sprintf(w,size>=0 ? "%d":"", info->blocks); break;
  1218.         case 's': sprintf(w,size>=0 ? "%d":"<Dir>",size); break;
  1219.         case 'i': *w= size>=0 ? '-' : 'd';                break;
  1220.         case 'r':
  1221.         case 'u':
  1222.             if( *s=='r' ) func=itoa; else func=itok;
  1223.             strcpy( w,size>=0 ? (*func)(size) : "<Dir>");
  1224.             break;
  1225.         case 'n':
  1226.         case 'q':
  1227.             strcpy(w,FilePart((char *)(info+1)));
  1228.             if( *s=='q' && size<0 ) strcat(w,"/");
  1229.             break;
  1230.         case 'l':
  1231.             if( info->flags & INFO_COMMENT ) *w='\n';
  1232.             break;
  1233.         case 'c':
  1234.             *w= info->flags & INFO_COMMENT ? 'c' : '-';
  1235.             break;
  1236.         case 'e':
  1237.             *w= info->flags & INFO_INFO ? 'i' : '-';
  1238.             break;
  1239.         case '+':
  1240.             *w= info->flags & INFO_INFO ? '+' : ' ';
  1241.             break;
  1242.         case 'L':
  1243.         case 'N':
  1244.             if (*s=='N')
  1245.                 strcpy(w,FilePart((char *)(info+1)));
  1246.             else
  1247.                 strcpy(w,"");
  1248.             if (info->type==ST_SOFTLINK) {
  1249.                 strcat(w," -> ");
  1250.                 ReadSoftLink((char *)(info+1),w+strlen(w),256);
  1251.             }
  1252.             else if (info->type==ST_LINKDIR || info->type==ST_LINKFILE) {
  1253.                 BPTR lock;
  1254.                 if (lock=Lock((char *)(info+1),ACCESS_READ)) {
  1255.                     strcat(w," -> ");
  1256.                     if (!NameFromLock(lock,w+strlen(w),256)) {
  1257.                         fprintf(stderr,"csh.lformat: NameFromLock() failed\n");
  1258.                         strcpy(w+strlen(w),(char *)(info+1));
  1259.                     }
  1260.                     UnLock(lock);
  1261.                 }
  1262.             }
  1263.             break;
  1264.         case 'I':
  1265.             switch (info->type) {
  1266.                 case ST_SOFTLINK:
  1267.                     *w='S';
  1268.                     break;
  1269.                 case ST_LINKDIR:
  1270.                 case ST_LINKFILE:
  1271.                     *w='H';
  1272.                     break;
  1273.                 case ST_PIPEFILE:
  1274.                     *w='P';
  1275.                     break;
  1276.                 default:
  1277.                     *w='-';
  1278.                     break;
  1279.             }
  1280.             break;
  1281.         case 'f': /* standard flags */
  1282.             for (i=7; i>=0; i--)
  1283.                 *w++ = (info->flags^15) & (1L<<i) ? "hsparwed"[7-i] : '-';
  1284.             *w=0;
  1285.             break;
  1286.         case 'F': /* group/other flags */
  1287.             for (i=3; i>=0; i--)
  1288.                 *w++ = (info->flags^15) & (1L<<(i+8)) ? "rwed"[3-i] : '-';
  1289.             *w++ = ' ';
  1290.             for (i=3; i>=0; i--)
  1291.                 *w++ = (info->flags^15) & (1L<<(i+12)) ? "rwed"[3-i] : '-';
  1292.             *w=0;
  1293.             break;
  1294.         case 'U': /* user-id */
  1295.             sprintf(w,"%d",info->uid);
  1296.             break;
  1297.         case 'G': /* group-id */
  1298.             sprintf(w,"%d",info->gid);
  1299.             break;
  1300.         case 'a':
  1301.             if( Stamp.ds_Days!=0 ) {
  1302.                 mi =Stamp.ds_Days*1440 + Stamp.ds_Minute;
  1303.                 mi-=info->date.ds_Days*1440 + info->date.ds_Minute;
  1304.             }
  1305.             sprintf(w,mi>=0?"%4d days %02d:%02d":"Future    ",
  1306.                       mi/1440,mi/60%60,mi%60);
  1307.             break;
  1308.         case 'o':
  1309.             if( dp=dopen( (char *)(info+1), &stat )) {
  1310.                 strcpy( w, dp->fib->fib_Comment );
  1311.                 dclose( dp );
  1312.             }
  1313.             break;
  1314.         case 'v':
  1315.         case 'w':
  1316.             if( *s=='v' ) func=itoa; else func=itok;
  1317.             dlen=dblocks=0;
  1318.             if( size<0 ) {
  1319.                 newrecurse( SCAN_DIR|SCAN_FILE|SCAN_RECURSE,
  1320.                             (char *)(info+1),count);
  1321.                 strcpy( w, (*func)(dlen));
  1322.                 info->size=size=dlen; info->blocks=dblocks;
  1323.             } else
  1324.                 strcpy( w, (*func)(size));
  1325.             break;
  1326.         case 'k':
  1327.             if( *info->class!=1 )
  1328.                 strcpy(w,info->class);
  1329.             else if( class=getclass((char *)(info+1)))
  1330.                 if( w=index(strncpy(w,class,50),0xA0) )
  1331.                     *w=0;
  1332.             break;
  1333.         case 'x':
  1334.         case 'd':
  1335.             sprintf(w,"%9s",dates(&info->date,*s=='x'));
  1336.             if(t=index(w,' ')) *t=0;
  1337.             break;
  1338.         case 't':
  1339.             sprintf(w,"%8s", next_word(dates(&info->date,0)));
  1340.             break;
  1341.         case 'm': MultiCol=form; form=0;      break;
  1342.         case '%': *w=*++s;                    break;
  1343.         case  0 : *w='%';                     break;
  1344.         default : *w='%';  *w++=*s; *w=0;     break;
  1345.         }
  1346.         if( cut ) buf[form]=0;
  1347.         *d=0; s++;
  1348.         d+=sprintf(d,sign<0?"%-*s":"%*s",form,buf);
  1349.     }
  1350.     if( MultiCol==-1 ) { *d++='\n'; }
  1351.     *d=0;
  1352. }
  1353.  
  1354.  
  1355.  
  1356. extern BOOL nologout;    /* defined in main.c */
  1357.  
  1358. int
  1359. do_quit( void )
  1360. {
  1361.     if (Src_stack) {
  1362.         Quit = 1;
  1363.         return(do_return());
  1364.     }
  1365.     if (!nologout) {
  1366.         if( exists("S:.logout"))
  1367.             execute("source S:.logout");
  1368.     }
  1369.     main_exit(0);
  1370.     return 0;
  1371. }
  1372.  
  1373. int
  1374. do_echo( void )
  1375. {
  1376.     char *args=compile_av(av,1,ac,' ',0);
  1377.     fprintf( (options&2)?stderr:stdout, (options&1)?"%s":"%s\n",args );
  1378.     free(args);
  1379.     return 0;
  1380. }
  1381.  
  1382.  
  1383. static int
  1384. breakcheckd(void)
  1385. {
  1386.     long sigs = SetSignal(0L,0L);
  1387.     int ret=!o_nobreak && (sigs & SIGBREAKF_CTRL_D);
  1388.     if (ret)
  1389.         fprintf(stderr,"^D\n");
  1390.     return ret;
  1391. }
  1392.  
  1393. static int
  1394. breakchecke(void)
  1395. {
  1396.     long sigs = SetSignal(0L,0L);
  1397.     int ret=!o_nobreak && (sigs & SIGBREAKF_CTRL_E);
  1398.     if (ret)
  1399.         fprintf(stderr,"^E\n");
  1400.     return ret;
  1401. }
  1402.  
  1403.  
  1404. /* gets a line from file, joining lines if they end in '\' */
  1405.  
  1406. #define MAXLINE 512
  1407.  
  1408. static int
  1409. srcgets(char **buf, int *buflen, FILE *file)
  1410. {
  1411.     char *bufptr=*buf, *p, *new, concat=0, cont;
  1412.     int   totlen=0, len;
  1413.  
  1414.     do {
  1415.         if( totlen+MAXLINE > *buflen ) {
  1416.             new=salloc(*buflen *= 2);
  1417.             memcpy( new, *buf, 1+bufptr-*buf );
  1418.             bufptr+= new-*buf;
  1419.             free(*buf);
  1420.             *buf=new;
  1421.         }
  1422.         if (fgets(bufptr, MAXLINE, file)==NULL) {
  1423.             if( concat )
  1424.                 fprintf(stderr,"Source: missing '}'\n");
  1425.             else if (bufptr != *buf)
  1426.                 fprintf(stderr,"Source: file ends in '\\'\n");
  1427.             return -1;
  1428.         }
  1429.         len= strlen( bufptr );
  1430.         totlen+= len;
  1431.  
  1432.         cont=0;
  1433.  
  1434.         p=bufptr+len-1;
  1435.         if(  p>=bufptr && *p=='\n') *p--=0;
  1436.         if(  p< bufptr   ) ;
  1437.         else if( *p=='\\') *p--=0, cont=1;
  1438.         else if( *p=='{' ) concat++;
  1439.         else if( *p=='}' ) {
  1440.             if( concat>0 ) {
  1441.                 concat--;
  1442.                 if( concat ) *++p='\n';
  1443.             }
  1444.         } else if( concat ) *++p='\n';
  1445.         bufptr=++p;
  1446.     } while( cont || concat );
  1447.     *bufptr=0;
  1448.     return totlen;
  1449. }
  1450.  
  1451.  
  1452.  
  1453. int
  1454. do_source( char *str )
  1455. {
  1456.     FILE *fi;
  1457.     char *buf;
  1458.     ROOT *root;
  1459.     int  retcode, len, bufsize=512+MAXLINE;
  1460.     int j;
  1461.     char *ptr;
  1462.  
  1463.     if (Src_stack == MAXSRC) {
  1464.         ierror(NULL,217);
  1465.         return -1;
  1466.     }
  1467.  
  1468.     if ((fi = fopen (av[1], "r")) == 0)
  1469.         { pError(av[1]); return -1;    }
  1470.  
  1471.     push_locals(root=(ROOT *)salloc( sizeof(ROOT)));
  1472.     buf=salloc(bufsize);
  1473.  
  1474.     set_var(LEVEL_SET | LEVEL_LOCAL, v_passed, next_word(next_word(str)));
  1475.  
  1476.  
  1477.     /*
  1478.      * now create a bunch of positional parameters , $0, $1 etc
  1479.      */
  1480.     j = 0;
  1481.     ptr = next_word (str);
  1482.     while (*ptr) {
  1483.         char *var;
  1484.         char p[6];
  1485.         char npos[6];
  1486.  
  1487.         var = ptr;
  1488.         sprintf (p, "%d", j);
  1489.         /*
  1490.          * term var str
  1491.          */
  1492.         ptr = next_word (ptr);
  1493.  
  1494.         /* printf("%s\n" , ptr); */
  1495.  
  1496.         if (*ptr)
  1497.             *(ptr - 1) = '\0';
  1498.  
  1499.         set_var (LEVEL_SET | LEVEL_LOCAL, p, var);
  1500.         /*
  1501.          * now set up what should be $# ( number of positionals )
  1502.          */
  1503. #if 0
  1504.         sprintf (p, "_N");    /* should be "#" but csh barfs :( */
  1505. #endif
  1506.         sprintf (p, "#");    /* hackin' */
  1507.         sprintf (npos, "%d", j++);
  1508.         set_var (LEVEL_SET | LEVEL_LOCAL, p, npos);
  1509.     }
  1510.  
  1511.  
  1512.     Src_pos  [Src_stack] = 0;
  1513.     Src_abort[Src_stack] = 0;
  1514.     Src_base [Src_stack] = fi;
  1515.     Src_if[Src_stack]=If_stack;
  1516.     ++Src_stack;
  1517.     while ((len=srcgets(&buf, &bufsize, fi))>=0&& !dobreak()&& !breakcheckd()){
  1518.         Src_pos[Src_stack-1] += len;
  1519.         if (Verbose&VERBOSE_SOURCE && !forward_goto)
  1520.             if( Verbose&VERBOSE_HILITE )
  1521.                 fprintf(stderr,"%s)%s%s\n",o_hilite,buf,o_lolite);
  1522.             else
  1523.                 fprintf(stderr,")%s\n",buf);
  1524.         retcode=execute(buf);
  1525.         if( retcode>=o_failat || Src_abort[Src_stack-1] )
  1526.             break;
  1527.         retcode=0;
  1528.     }
  1529.     --Src_stack;
  1530.     if( If_stack>Src_if[Src_stack] )
  1531.         If_stack=Src_if[Src_stack], disable=If_stack && If_base[If_stack-1];
  1532.  
  1533.     if (forward_goto) ierror(NULL,501);
  1534.     forward_goto = 0;
  1535.     unset_level(LEVEL_LABEL+ Src_stack);
  1536.     unset_var(LEVEL_SET, v_gotofwd);
  1537.     unset_var(LEVEL_SET, v_passed);
  1538.     fclose (fi);
  1539.  
  1540.     pop_locals();
  1541.     free(buf);
  1542.     free(root);
  1543.  
  1544.     return retcode;
  1545. }
  1546.  
  1547. /* set process cwd name and $_cwd, if str != NULL also print it. */
  1548.  
  1549. void
  1550. set_cwd(void)
  1551. {
  1552.     char pwd[256];
  1553.  
  1554.     if (!NameFromLock(Myprocess->pr_CurrentDir, pwd, 254)) {
  1555.         fprintf(stderr,"csh.set_cwd: NameFromLock() failed\n");
  1556.         strcpy(pwd,"<unknown>");
  1557.     }
  1558.     set_var(LEVEL_SET, v_cwd, pwd);
  1559.     /* put the current dir name in our CLI task structure */
  1560.     CtoBStr(pwd, Mycli->cli_SetName, 254);
  1561. }
  1562.  
  1563. int
  1564. do_pwd( void )
  1565. {
  1566.     set_cwd();
  1567.     puts( get_var( LEVEL_SET, v_cwd ));
  1568.     return 0;
  1569. }
  1570.  
  1571.  
  1572. /*
  1573.  * CD
  1574.  *
  1575.  * CD(str, 0)      -do CD operation.
  1576.  *
  1577.  */
  1578.  
  1579. extern int qcd_flag;
  1580.  
  1581. static char lastqcd[80];
  1582. static FILE *qcdfile;
  1583. static int  NumDirs;
  1584.  
  1585. static int
  1586. countfunc( long mask, char *file, char *fullpath )
  1587. {
  1588.     fprintf( qcdfile, "%s\n", fullpath );
  1589.     fprintf( stdout, "\r Directories: %d", ++NumDirs );
  1590.     fflush ( stdout );
  1591.     return 0;
  1592. }
  1593.  
  1594. int
  1595. do_cd(void)
  1596. {
  1597.     BPTR oldlock, filelock;
  1598.     char buf[100], *old, *str=av[1];
  1599.     int  i=1, repeat;
  1600.  
  1601.     if( options & 1 ) {
  1602.         if( !o_csh_qcd ) { fprintf(stderr,"$_qcd unset\n"); return 20; }
  1603.         if( !(qcdfile=fopen( o_csh_qcd, "w" )))
  1604.             { fprintf(stderr,"Can't open output\n"); return 20; }
  1605.         for( ; i<ac && !dobreak(); i++ ) {
  1606.             NumDirs=0;
  1607.             printf("%s\n",av[i]);
  1608.             newrecurse( SCAN_DIRENTRY | SCAN_RECURSE, av[i], countfunc );
  1609.             printf("\n");
  1610.         }
  1611.         fclose(qcdfile);
  1612.         return 0;
  1613.     }
  1614.  
  1615.     if ( !str || !(*str) ) {    /* old "!*str" causes enforcer hit! */
  1616.         printf("%s\n", get_var( LEVEL_SET, v_cwd ));
  1617.         return 0;
  1618.     }
  1619.  
  1620.     if (filelock=Lock(str,ACCESS_READ)) {
  1621.         lastqcd[0]=0;
  1622.         if (!isdir(str)) { UnLock(filelock); ierror(str,212); return 20; }
  1623.     } else {
  1624.         repeat= !strncmp( lastqcd, str, 79 );
  1625.         strncpy( lastqcd, str, 79);
  1626.  
  1627.         if( !quick_cd( buf, av[i], repeat) )
  1628.             { fprintf(stderr,"Object not found %s\n",str); return 20; }
  1629.         if (!(filelock=Lock(buf,ACCESS_READ)))
  1630.             { pError(buf); return 20; }
  1631.     }
  1632.     if (oldlock=CurrentDir(filelock)) UnLock(oldlock);
  1633.     if( !(old=get_var(LEVEL_SET, v_cwd)) )
  1634.         old="";
  1635.     set_var(LEVEL_SET, v_lcd, old);
  1636.     set_cwd();
  1637.  
  1638.     return 0;
  1639. }
  1640.  
  1641. char *
  1642. quick_cd( char *buf, char *name, int repeat )
  1643. {
  1644.     if( !o_csh_qcd || !exists(o_csh_qcd))
  1645.         return NULL;
  1646.     qcd_flag=repeat ? 2 : 1;
  1647.     strcpy(buf,name);
  1648.     if( quicksearch( o_csh_qcd, 1, buf)!=2 )
  1649.         return NULL;
  1650.     return buf;
  1651. }
  1652.  
  1653.  
  1654. /* AMK: mkdir now builds path to destination directory if neccessary */
  1655. int
  1656. do_mkdir( void )
  1657. {
  1658.     int i;
  1659.     BPTR lock;
  1660.     char *p,c;
  1661.  
  1662.     for (i=1; i<ac; ++i) {
  1663.  
  1664.         /* Are there any sub-directories to build? */
  1665.         if( options&1 && (p=strchr(av[i],'/'))) {
  1666.             do {
  1667.                 c = *p;
  1668.                 *p = '\0';
  1669.                 if (lock=CreateDir(av[i]))
  1670.                     UnLock(lock);
  1671.                 *p = c;
  1672.             } while(p=strchr(++p,'/'));
  1673.         }
  1674.  
  1675.         /* allow trailing slash */
  1676.         if (lastch(av[i]) == '/' )
  1677.             av[i][strlen(av[i])-1] = '\0';
  1678.  
  1679.         /* Okay, sub-directories should exist, now try normal mkdir. */
  1680.  
  1681.         if (lock=CreateDir(av[i]))
  1682.             UnLock(lock);
  1683.         else
  1684.             pError(av[i]);
  1685.  
  1686.     }
  1687.  
  1688.     return 0;
  1689. }
  1690.  
  1691. int
  1692. do_mv( void )
  1693. {
  1694.     char *dest, buf[256];
  1695.     int dirflag, i, len;
  1696.  
  1697.     dirflag=isdir(dest=av[--ac]);
  1698.     if (ac>3 && !dirflag) { ierror(dest, 507); return (-1); }
  1699.     for (i=1; i<ac; ++i) {
  1700.         strcpy(buf, dest);
  1701.  
  1702.         /* source: remove trailing slash */
  1703.         if ((len=strlen(av[i]))>1 && av[i][len-1]=='/' && av[i][len-2]!=':' && av[i][len-2]!='/')
  1704.             av[i][len-1] = '\0';
  1705.  
  1706.         /* destination: remove trailing slash */
  1707.         if ((len=strlen(buf))>1 && buf[len-1]=='/' && buf[len-2]!=':' && buf[len-2]!='/')
  1708.             buf[len-1] = '\0';
  1709.  
  1710.         if (dirflag && stricmp(av[i],buf))
  1711.              AddPart(buf, FilePart(av[i]), 255L);
  1712.  
  1713.         if (Rename(av[i], buf)==0) {
  1714.             pError(av[i]);
  1715.             if (!(options&1))
  1716.                 return -1;
  1717.         }
  1718.         else {
  1719.             clear_archive_bit( buf );
  1720.             if (options&2) {
  1721.                 /*printf("Renaming %s as %s\n",av[i],buf);*/
  1722.                 printf(" %s...%s\n",av[i],dirflag?"moved":"renamed");
  1723.             }
  1724.         }
  1725.     }
  1726.     return 0;
  1727. }
  1728.  
  1729. static char *searchstring;
  1730. static char docr;
  1731.  
  1732. #if 0
  1733. int
  1734. all_args( int (*action)FUNCARG(long,char*,char*), int dirsflag )
  1735. {
  1736.     int  i;
  1737.     long mask= SCAN_FILE;
  1738.  
  1739.     if( options&1 )
  1740.         mask |= SCAN_RECURSE;
  1741.     if( dirsflag )
  1742.         mask |= SCAN_DIR;
  1743.  
  1744.     for ( i=1; i<ac && !dobreak(); ++i)
  1745.         if (isdir(av[i])) {
  1746.             if (options & 1)
  1747.                 newrecurse(mask, av[i], action);
  1748.             if (dirsflag)
  1749.                 (*action)(SCAN_DIR,av[i],av[i]);
  1750.         } else
  1751.             (*action)(SCAN_FILE,av[i],av[i]);
  1752.     if(docr) printf("\n"),docr=0;
  1753.     dobreak();
  1754.     return 0;
  1755. }
  1756. #endif
  1757.  
  1758. /* this is all_args() but with a user definable range from n to m */
  1759. int
  1760. all_args_n2m( int (*action)FUNCARG(long,char*,char*), int dirsflag, int aa_from, int aa_to )
  1761. {
  1762.     int  i;
  1763.     long mask= SCAN_FILE;
  1764.  
  1765.     if( options&1 )
  1766.         mask |= SCAN_RECURSE;
  1767.     if( dirsflag )
  1768.         mask |= SCAN_DIR;
  1769.  
  1770.     for ( i=aa_from; i<aa_to && !dobreak(); ++i)
  1771.         if (isdir(av[i])) {
  1772.             if (options & 1)
  1773.                 newrecurse(mask, av[i], action);
  1774.             if (dirsflag)
  1775.                 (*action)(SCAN_DIR,av[i],av[i]);
  1776.         } else
  1777.             (*action)(SCAN_FILE,av[i],av[i]);
  1778.     if(docr) printf("\n"),docr=0;
  1779.     dobreak();
  1780.     return 0;
  1781. }
  1782.  
  1783. int
  1784. all_args( int (*action)FUNCARG(long,char*,char*), int dirsflag )
  1785. {
  1786.     return( all_args_n2m(action,dirsflag,1,ac) );
  1787. }
  1788.  
  1789. #define SEARCH_REC   1
  1790. #define SEARCH_CASE  2
  1791. #define SEARCH_WILD  4
  1792. #define SEARCH_NUM   8
  1793. #define SEARCH_EXCL  16
  1794. #define SEARCH_QUIET 32
  1795. #define SEARCH_VERB  64
  1796. #define SEARCH_BIN   128
  1797. #define SEARCH_FILE  256
  1798. #define SEARCH_ABORT 512
  1799. #define SEARCH_LEFT  1024
  1800. #define SEARCH_ONLY  2048
  1801.  
  1802. /* added by amk, not yet implemented */
  1803. #define SEARCH_STYLE 4096    /* alternative style, inspired by GMD */
  1804. #define SEARCH_ONCE  8192    /* only show first pattern match per file */
  1805.  
  1806. static int abort_search;
  1807. static char lowbuf[256], file_name, file_cr;
  1808.  
  1809. static int
  1810. search_file( long mask, char *s, char *fullpath )
  1811. {
  1812.     PATTERN *pat;
  1813.     FILE *fi;
  1814.     char *p, *q;
  1815.     int nocasedep, lctr, len, excl=((options & 16) !=0 ), yesno;
  1816.     char buf[256], searchit[120], first, left;
  1817.  
  1818.     if( abort_search )
  1819.         return 0;
  1820.  
  1821.     nocasedep=!(options & SEARCH_CASE);
  1822.     lctr= docr= file_name= file_cr= 0;
  1823.     if (!(options & (SEARCH_QUIET|SEARCH_FILE))) {
  1824.         if( options & SEARCH_VERB )
  1825.             printf("Examining %s ...\n",fullpath);
  1826.         else
  1827.             printf("\015Examining %s ...\033[K",fullpath), docr=1;
  1828.         fflush( stdout );
  1829.     }
  1830.  
  1831.     strcpy(searchit,searchstring);
  1832.     if (options & SEARCH_WILD) strcat(searchit,"\n");
  1833.     len=strlen(searchit);
  1834.     if (nocasedep) strupr(searchit);
  1835.     first=*searchit;
  1836.  
  1837.     if( strcmp("STDIN",s) && !(options&SEARCH_WILD) && !excl ||
  1838.                  options&SEARCH_BIN )
  1839.         if( quicksearch(s,nocasedep,searchit) )
  1840.             return 0;
  1841.  
  1842.     if( options&SEARCH_BIN )
  1843.         { fprintf(stderr,"Out of memory\n"); return 20; }
  1844.  
  1845.     if(!(pat=compare_preparse( searchit, options&SEARCH_CASE )))
  1846.         { fprintf(stderr,"Invalid pattern\n"); return 20; }
  1847.  
  1848.     fi = strcmp("STDIN",s) ?  fopen(s,"r") : stdin;
  1849.     if (fi==NULL) { pError(s); return 20; }
  1850.  
  1851.     prepscroll(0);
  1852.  
  1853.     while (fgets(buf,256,fi) && !dobreak()) {
  1854.         lctr++; left=1;
  1855.         if (options & SEARCH_WILD)
  1856.             yesno=compare_ok(pat, p=buf);
  1857.         else {
  1858.             if (nocasedep) {
  1859.                 strcpy(lowbuf,buf);
  1860.                 strupr(lowbuf);
  1861.                 p=lowbuf;
  1862.             } else
  1863.                 p=buf;
  1864.             q=p;
  1865.             while ((p=index(p,first)) && strncmp(p++,searchit,len)) ;
  1866.             yesno= (p!=NULL);
  1867.             left = --p - q;
  1868.         }
  1869.         if( yesno ^ excl )
  1870.             if(!(options&SEARCH_ONLY)|| !isalphanum(p[-1])&&!isalphanum(p[len]))
  1871.                 if( found(buf, lctr, 0, s, left ) )
  1872.                     break;
  1873.     }
  1874.     compare_free(pat);
  1875.     if (fi!=stdin) fclose (fi);
  1876.     if( file_cr ) printf("\n");
  1877.     return 0;
  1878. }
  1879.  
  1880. int qcd_flag, qcd_offs;
  1881.  
  1882. #define READCHUNK 60000
  1883.  
  1884. static int
  1885. quicksearch( char *name, int nocasedep, char *pattern )
  1886. {
  1887.     int i, ptrn=strlen(pattern);
  1888.     char ut[256], *buffer, *lend;
  1889.     char *uptab=ut, *get, c, *lpos, *lstart;
  1890.     int len, lnum, qcd=qcd_flag, repeat=(qcd==2 && qcd_offs!=0), buflen;
  1891.     int sofar, got;
  1892.     BPTR fh;
  1893.  
  1894. #ifdef AZTEC_C
  1895.     while(0) while(0) c=c=0, uptab=uptab=ut, get=get=NULL;
  1896. #endif
  1897.  
  1898.     qcd_flag=0;
  1899.     if( !(fh=Open(name,MODE_OLDFILE))) {
  1900.         i=(long)IoErr(), docr=0;
  1901.         printf("\n");
  1902.         ierror(name,i);
  1903.         return 1;
  1904.     }
  1905.     len=filesize( name );
  1906.     buflen=len+3;
  1907.     if( !(buffer=(void *)AllocMem(buflen,0))) { Close(fh); return 0; }
  1908.     sofar=0;
  1909.     do {
  1910.         got=Read( fh, (char *)buffer+sofar, READCHUNK);
  1911.         sofar+=got;
  1912.     } while( got==READCHUNK );
  1913.     Close( fh);
  1914.     if( sofar != len ) {
  1915.         FreeMem( buffer, buflen );
  1916.         pError(pattern); return 1;
  1917.     }
  1918.     if(buffer[len-1]!='\n')
  1919.         buffer[len++]='\n';
  1920.  
  1921.     if( nocasedep )
  1922.         strupr( pattern );
  1923.  
  1924.     if( !qcd )
  1925.         prepscroll(0);
  1926.  
  1927.     for( i=0; i<256; i++ ) uptab[i]=i;
  1928.     if( nocasedep ) for( i='a'; i<='z'; i++ ) uptab[i]=i-'a'+'A';
  1929. retry:
  1930.     c=*pattern, buffer[len]=c, buffer[len+1]=c;
  1931.     get= (qcd==2) ? buffer+qcd_offs : buffer;
  1932.     if( qcd==1 ) qcd_offs=0;
  1933.  
  1934.     lpos=lstart=buffer, lnum=1;
  1935.     for( ;; ) {
  1936.         do ; while( uptab[*get++]!=c );
  1937.         if( --get>=buffer + len )
  1938.             break;
  1939.         for( i=1; i<ptrn; i++ )
  1940.             if( uptab[get[i]]!=pattern[i] )
  1941.                 break;
  1942.         if( i==ptrn ) {
  1943.             for( ;lpos<get; lpos++ )
  1944.                 if( *lpos=='\n' )
  1945.                     lstart=lpos+1, lnum++;
  1946.             for( lend=lstart+1; *lend!='\n'; lend++ ) ;
  1947.             if( qcd ) {
  1948.                 if( get[-1]==':' || get[-1]=='/' ||
  1949.                       lpos==lstart && lend[-1]==':' ) {
  1950.                     char *tmp;
  1951.                     for( tmp=get+ptrn; *tmp&& *tmp!='\n'&& *tmp!='/'; tmp++ );
  1952.                     if( *tmp!='/' ) {
  1953.                         *lend=0;
  1954.                         strncpy(pattern,lstart,79);
  1955.                         qcd_offs=lend-buffer;
  1956.                         FreeMem( buffer, buflen );
  1957.                         return 2;
  1958.                     }
  1959.                 } else 
  1960.                     lend=lpos+1;
  1961.             } else {
  1962.                 *lend=0;
  1963.                 if(!(options&SEARCH_ONLY) ||
  1964.                      !isalphanum(lpos[-1])&&!isalphanum(lpos[ptrn]))
  1965.                     if(found(lstart, lnum, get-buffer, name, lpos==lstart ))
  1966.                         break;
  1967.                 *lend='\n';
  1968.             }
  1969.             get=lend+1;
  1970.         } else
  1971.             get++;
  1972.     }
  1973.     if( repeat )  { repeat=0; qcd_offs=0; goto retry; }
  1974.     if( file_cr ) { printf("\n"); quickscroll(); }
  1975.     FreeMem( buffer, buflen );
  1976.     return 1;
  1977. }
  1978.  
  1979. static int
  1980. found( char *lstart, int lnum, int loffs, char *name, char left )
  1981. {
  1982.     int fileabort=0;
  1983.  
  1984.     if( (options&SEARCH_LEFT) && !left)
  1985.         return 0;
  1986.  
  1987.     if ( docr )
  1988.         { quickscroll(); printf("\n"); docr=0; }
  1989.  
  1990.     if( options&SEARCH_FILE ) {
  1991.         file_cr=1;
  1992.         if( !file_name )
  1993.             printf("%s",name), file_name=1;
  1994.         if( options&SEARCH_NUM )
  1995.             fileabort=1;
  1996.         else
  1997.             printf(" %d",lnum);
  1998.     } else if( options & SEARCH_BIN ) {
  1999.         if (!(options & SEARCH_NUM))
  2000.             printf("Byte offset %d\n",loffs);
  2001.         else
  2002.             printf("%d\n",loffs);
  2003.         quickscroll();
  2004.     } else {
  2005.         if (!(options & SEARCH_NUM))
  2006.             printf("%4d ",lnum);
  2007.         printf((lstart[strlen(lstart)-1]=='\n')?"%s":"%s\n",lstart);
  2008.         quickscroll();
  2009.     }
  2010.     abort_search= options&SEARCH_ABORT;
  2011.     return dobreak() || fileabort || abort_search;
  2012. }
  2013.  
  2014. int
  2015. do_search( void )
  2016. {
  2017.     if(!isconsole(Output())) options |= SEARCH_VERB;
  2018.     abort_search=0;
  2019.     searchstring=av[--ac];
  2020.     all_args(search_file, 0);
  2021.     return 0;
  2022. }
  2023.  
  2024. #if 0
  2025. /* do_grep() is just do_search() with a modified all_args() */
  2026. int
  2027. do_grep( void )
  2028. {
  2029.     if(!isconsole(Output())) options |= SEARCH_VERB;
  2030.     abort_search=0;
  2031.     searchstring=av[1];
  2032.     all_args_n2m(search_file, 0, 2, ac);
  2033.     return 0;
  2034. }
  2035. #endif
  2036.  
  2037. static BOOL rm_error_abort = FALSE;
  2038. static int rm_file( long mask, char *file, char *fullpath )
  2039. {
  2040.     if (rm_error_abort)
  2041.         return(20);
  2042.  
  2043.     if ( *file && file[strlen(file)-1]=='/' ) {
  2044.         file[strlen(file)-1]=0;
  2045.     }
  2046.     if (options&16 || has_wild) {
  2047.         fprintf(stdout," %s...",fullpath);
  2048.         fflush(stdout);
  2049.     }
  2050.     if (options&2 || options&4) {
  2051.         SetProtection(file,0L);
  2052.     }
  2053.     if (!DeleteFile(file)) {
  2054.         pError(file);
  2055.         if (options & 8) {
  2056.             rm_error_abort = TRUE;
  2057.             return 20;
  2058.         }
  2059.     } else if (options&16 || has_wild)
  2060.         fprintf(stdout,"Deleted\n");
  2061.  
  2062.     return 0;
  2063. }
  2064.  
  2065. int
  2066. do_rm( void )
  2067. {
  2068.     rm_error_abort = FALSE;
  2069.     all_args( rm_file, 1);
  2070.     rm_error_abort = FALSE;
  2071.     return 0;
  2072. }
  2073.  
  2074.  
  2075. int
  2076. do_history( void )
  2077. {
  2078.     HIST *hist;
  2079.     int i = H_tail_base;
  2080.     int len = av[1] ? strlen(av[1]) : 0;
  2081.     char buf[250];
  2082.  
  2083.     if( options&2 ) {
  2084.         while( safegets(buf,stdin) )
  2085.             add_history(buf);
  2086.         return 0;
  2087.     }
  2088.  
  2089.     for (hist = H_tail; hist && !dobreak(); hist = hist->prev, i++)
  2090.         if (len == 0 || !strncmp(av[1], hist->line, len))
  2091.             if( options&1 )
  2092.                 printf("%s\n", hist->line);
  2093.             else
  2094.                 printf("%3d %s\n", i, hist->line);
  2095.     return 0;
  2096. }
  2097.  
  2098. int
  2099. do_mem( void )
  2100. {
  2101.     static long clast, flast;
  2102.     long cfree, ffree, i;
  2103.     char *desc="Free", *mem;
  2104.  
  2105.     if( options&32 )
  2106.         for( i=0; i<10; i++ )
  2107.             if(mem=(char*)AllocMem(0x7fffffff,0))
  2108.                 FreeMem(mem,0x7fffffff);
  2109.  
  2110.     Forbid();
  2111.     cfree = AvailMem (MEMF_CHIP);
  2112.     ffree = AvailMem (MEMF_FAST);
  2113.     Permit();
  2114.     if( options&8 ) {
  2115.         clast=cfree, flast=ffree;
  2116.         return 0;
  2117.     }
  2118.     if( options&16 )
  2119.         cfree=clast-cfree, ffree=flast-ffree, desc="Used";
  2120.     if( options&4 ) {
  2121.         if     ( options & 1 ) printf("%ld\n",cfree);
  2122.         else if( options & 2 ) printf("%ld\n",ffree);
  2123.         else                   printf("%ld\n",cfree+ffree);
  2124.     } else {
  2125.         if     ( options & 1 ) printf("Free CHIP memory:%10s\n",itoa(cfree));
  2126.         else if( options & 2 ) printf("Free FAST memory:%10s\n",itoa(ffree));
  2127.         else {
  2128.             if(ffree) {
  2129.                 printf("FAST memory:%10s\n",itoa(ffree));
  2130.                 printf("CHIP memory:%10s\n",itoa(cfree));
  2131.             }
  2132.             printf("Total  %s:%10s\n",desc,itoa(cfree+ffree));
  2133.         }
  2134.     }
  2135.     return 0;
  2136. }
  2137.  
  2138. int
  2139. do_forline( void )
  2140. {
  2141.     char vname[33], buf[256], *cstr;
  2142.     int lctr;
  2143.     FILE *f;
  2144.  
  2145.     strcpy(vname,av[1]);
  2146.     if( !strcmp(av[2],"STDIN") )
  2147.         f=stdin;
  2148.     else 
  2149.         if(!(f=fopen(av[2],"r"))) { pError(av[2]); return 20; }
  2150.  
  2151.     lctr=0;
  2152.     ++H_stack;
  2153.     cstr = compile_av (av, 3, ac, ' ', 0);
  2154.     while (fgets(buf,256,f) && !dobreak() && !breakcheckd()) {
  2155.         buf[strlen(buf)-1]='\0';    /* remove CR */
  2156.         lctr++;
  2157.         set_var(LEVEL_SET | LEVEL_LOCAL, vname, buf);
  2158.         sprintf(buf,"%d",lctr);
  2159.         set_var(LEVEL_SET | LEVEL_LOCAL, v_linenum, buf);
  2160.         exec_command(cstr);
  2161.     }
  2162.     if( f!=stdin ) fclose(f);
  2163.     --H_stack;
  2164.     free (cstr);
  2165.     if( lctr ) {
  2166.         unset_var (LEVEL_SET, vname);
  2167.         unset_var (LEVEL_SET, v_linenum);
  2168.     }
  2169.     return 0;
  2170. }
  2171.  
  2172. int
  2173. do_fornum( void )
  2174. {
  2175.     char vname[33], buf[16];
  2176.     int n1, n2, step, i=1, verbose, runs=0;
  2177.     char *cstr;
  2178.  
  2179.     verbose=(options & 1);
  2180.     strcpy(vname,av[i++]);
  2181.     n1=myatoi(av[i++],-32767,32767); if (atoierr) return 20;
  2182.     n2=myatoi(av[i++],-32767,32767); if (atoierr) return 20;
  2183.     if (options & 2) {
  2184.         step=myatoi(av[i++],-32767,32767); if (atoierr) return 20;
  2185.     } else
  2186.         step=1;
  2187.     ++H_stack;
  2188.     cstr = compile_av (av, i, ac, ' ', 0);
  2189.     for (i=n1; (step>=0 ? i<=n2 : i>=n2) && !CHECKBREAK() && !breakcheckd();
  2190.          i+=step, runs++) {
  2191.         if (verbose) fprintf(stderr, "fornum: %d\n", i);
  2192.         sprintf(buf,"%d",i);
  2193.         set_var (LEVEL_SET | LEVEL_LOCAL, vname, buf);
  2194.         exec_command(cstr);
  2195.     }
  2196.     --H_stack;
  2197.     free (cstr);
  2198.     if( runs )
  2199.         unset_var (LEVEL_SET, vname);
  2200.     return 0;
  2201. }
  2202.  
  2203. /*
  2204.  * foreach var_name  ( str str str str... str ) commands
  2205.  * spacing is important (unfortunately)
  2206.  *
  2207.  * ac=0    1 2 3 4 5 6 7
  2208.  * foreach i ( a b c ) echo $i
  2209.  * foreach i ( *.c ) "echo -n "file ->";echo $i"
  2210.  */
  2211.  
  2212. int
  2213. do_foreach( void )
  2214. {
  2215.     int cstart, cend;
  2216.     char *cstr, vname[33];
  2217.     char **fav;
  2218.     int i=1, verbose;
  2219.  
  2220.     verbose=(options & 1);
  2221.     strcpy(vname, av[i++]);
  2222.     if (*av[i] == '(') i++;
  2223.     cstart = i;
  2224.     while (i<ac && *av[i] != ')') i++;
  2225.     if (i > ac) { fprintf(stderr,"')' expected\n"); return 20; }
  2226.     ++H_stack;
  2227.     cend = i;
  2228.  
  2229.     fav = (char **)salloc(sizeof(char *) * (ac));
  2230.     for (i = cstart; i < cend; ++i) fav[i] = av[i];
  2231.  
  2232.     cstr = compile_av (av, cend + 1, ac, ' ', 0);
  2233.  
  2234.     for (i = cstart; i<cend && !CHECKBREAK() && !breakcheckd() && !breakchecke(); ++i) {
  2235.         set_var (LEVEL_SET | LEVEL_LOCAL, vname, fav[i]);
  2236.         if (verbose) fprintf(stderr, "foreach: %s\n", fav[i]);
  2237.         execute(cstr);
  2238.     }
  2239.     --H_stack;
  2240.     free (fav);
  2241.     free (cstr);
  2242.     if( cstart<cend)
  2243.         unset_var (LEVEL_SET, vname);
  2244.     return 0;
  2245. }
  2246.  
  2247. int
  2248. do_forever( char *str )
  2249. {
  2250.     int rcode = 0;
  2251.     char *ptr = next_word( str );
  2252.  
  2253.     ++H_stack;
  2254.     for (;;) {
  2255.         if (CHECKBREAK() || breakcheckd()) { rcode = 20; break; }
  2256.         if (exec_command (ptr) > 0) {
  2257.             str = get_var(LEVEL_SET, v_lasterr);
  2258.             rcode = (str) ? atoi(str) : 20;
  2259.             break;
  2260.         }
  2261.     }
  2262.     --H_stack;
  2263.     return rcode;
  2264. }
  2265.  
  2266. extern struct IntuitionBase *IntuitionBase;
  2267.  
  2268.  
  2269. int
  2270. do_window( void )
  2271. {
  2272.     long x=-1, y=-1, w=-1, h=-1, maxwidth, maxheight, arg[5];
  2273.     int i;
  2274.  
  2275.     if(options & 32) { /* -q */
  2276.         struct Screen *scrn;
  2277.         struct Window *window;
  2278.         ULONG ibase_lock;
  2279.         char **ibase_list=NULL;
  2280.         long i,ibase_num=0;
  2281.         char fmt[256];
  2282.  
  2283.         newwidth(); /* get current window width */
  2284.  
  2285.         ibase_lock = LockIBase(0);
  2286.  
  2287.         for (scrn=IntuitionBase->FirstScreen; scrn; scrn=scrn->NextScreen) {
  2288.  
  2289.             struct List *list;
  2290.             struct Node *node;
  2291.             UBYTE PubNameBuf[MAXPUBSCREENNAME+4] = "";
  2292.  
  2293.             list = LockPubScreenList();
  2294.             for (node = list->lh_Head; node->ln_Succ; node = node->ln_Succ) {
  2295.                 if (((struct PubScreenNode *)node)->psn_Screen == scrn)
  2296.                     sprintf(PubNameBuf," [%s]",node->ln_Name);
  2297.             }
  2298.             UnlockPubScreenList();
  2299.  
  2300.             sprintf(fmt,"Screen %c%.*s%c%s (%d,%d,%dx%dx%d):\n",
  2301.                 scrn->Title ? '\"' : '(',
  2302.                 (options&64) ? 128 : (((w_width-36-strlen(PubNameBuf)) > 0) ? (w_width-36-strlen(PubNameBuf)) : 30),
  2303.                 scrn->Title ? scrn->Title : "no title",
  2304.                 scrn->Title ? '\"' : ')',
  2305.                 PubNameBuf,
  2306.                 scrn->LeftEdge,
  2307.                 scrn->TopEdge,
  2308.                 scrn->Width,
  2309.                 scrn->Height,
  2310.                 scrn->BitMap.Depth
  2311.             );
  2312.             add_array_list(&ibase_list,&ibase_num,fmt);
  2313.  
  2314.             for (window=scrn->FirstWindow; window; window=window->NextWindow) {
  2315.                 sprintf(fmt,"   win %c%.*s%c (%d,%d,%dx%d)\n",
  2316.                     window->Title ? '\"' : '(',
  2317.                     (options&64) ? 128 : w_width-32,
  2318.                     window->Title ? window->Title : "no title",
  2319.                     window->Title ? '\"' : ')',
  2320.                     window->LeftEdge,
  2321.                     window->TopEdge,
  2322.                     window->Width,
  2323.                     window->Height
  2324.                 );
  2325.                 add_array_list(&ibase_list,&ibase_num,fmt);
  2326.             }
  2327.  
  2328.             if (scrn->NextScreen)
  2329.                 add_array_list(&ibase_list,&ibase_num,"\n");
  2330.         }
  2331.  
  2332.         UnlockIBase(ibase_lock);
  2333.  
  2334.         for(i=0; i<ibase_num; i++)
  2335.             printf("%s",ibase_list[i]);
  2336.  
  2337.         free_array_list(ibase_list,ibase_num);
  2338.  
  2339.         return 0;
  2340.     }
  2341.  
  2342.     if( o_nowindow || !Mywindow )
  2343.         return 20;
  2344.  
  2345.     maxwidth = Mywindow->WScreen->Width;
  2346.     maxheight= Mywindow->WScreen->Height;
  2347.     if( options&1 )
  2348.         x=Mywindow->LeftEdge,y=Mywindow->TopEdge,w=Mywindow->MinWidth,h=Mywindow->MinHeight;
  2349.     if( options&2 ) x=y=0, w=maxwidth, h=maxheight;
  2350.     if( options&4 ) WindowToFront(Mywindow);
  2351.     if( options&8 ) WindowToBack(Mywindow);
  2352.     if( options&16) ActivateWindow(Mywindow);
  2353.     if( ac >= 5) {
  2354.         for(i=1; i<5; i++) {
  2355.             arg[i] = myatoi(av[i],0,1023); if (atoierr) return 20;
  2356.         }
  2357.         x=arg[1]; y=arg[2]; w=arg[3]; h=arg[4];
  2358.     }
  2359.     if( w!=-1 ) {
  2360.         int i;
  2361.         if ( x+w>maxwidth || y+h>maxheight ) {
  2362.             ierror(NULL, 500);
  2363.             return 20;
  2364.         }
  2365.         if( w<Mywindow->MinWidth  ) w=Mywindow->MinWidth;
  2366.         if( h<Mywindow->MinHeight ) h=Mywindow->MinHeight;
  2367.         if( Mywindow->LeftEdge!=0 || Mywindow->TopEdge!=0 )
  2368.             MoveWindow(Mywindow, -Mywindow->LeftEdge, -Mywindow->TopEdge );
  2369.         if( Mywindow->Width!=w || Mywindow->Height!=h )
  2370.             SizeWindow(Mywindow, w-Mywindow->Width   , h-Mywindow->Height  );
  2371.         if( x || y )
  2372.             MoveWindow(Mywindow, x, y );
  2373.         for( i=0; i<10; i++ ) {
  2374.             if(  Mywindow->LeftEdge==x && Mywindow->TopEdge==y &&
  2375.                  Mywindow->Width   ==w && Mywindow->Height ==h )
  2376.                 break;
  2377.             Delay(5);
  2378.         }
  2379.     } else 
  2380.         Delay(20); /* pause 1/2 sec. before trying to print */
  2381.  
  2382.     Delay(10);
  2383.     printf("\014");
  2384.     return 0;
  2385. }
  2386.  
  2387. static void
  2388. setsystemtime(struct DateStamp *ds)
  2389. {
  2390.     struct timerequest tr;
  2391.     long secs= ds->ds_Days*86400+ds->ds_Minute*60+ds->ds_Tick/TICKS_PER_SECOND;
  2392.  
  2393.     if (OpenDevice(TIMERNAME, UNIT_VBLANK,(struct IORequest *)&tr, 0L)) {
  2394.         fprintf(stderr,"Clock error: can't open timer device\n");
  2395.         return;
  2396.     }
  2397.  
  2398.     tr.tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  2399.     tr.tr_node.io_Message.mn_Node.ln_Pri = 0L;
  2400.     tr.tr_node.io_Message.mn_Node.ln_Name = NULL;
  2401.     tr.tr_node.io_Message.mn_ReplyPort = NULL;
  2402.     tr.tr_node.io_Command = TR_SETSYSTIME;
  2403.     tr.tr_time.tv_secs = secs;
  2404.     tr.tr_time.tv_micro = 0L;
  2405.     if (DoIO ((struct IORequest *)&tr))
  2406.         fprintf(stderr,"Clock error: can't talk to timer device\n");
  2407.     CloseDevice ((struct IORequest *)&tr);
  2408. }
  2409.  
  2410. static char tday[LEN_DATSTRING+1];    /* not sure, if +1 (null byte) is neccessary */
  2411.  
  2412. char *
  2413. dates( struct DateStamp *dss, int flags )
  2414. {
  2415.     static char timestr[2*LEN_DATSTRING+1];
  2416.     char tdate[LEN_DATSTRING+1], ttime[LEN_DATSTRING+1];
  2417.     struct DateTime dt;
  2418.     struct DateStamp *myds;
  2419.     char *dp,*tp;
  2420.  
  2421.     dt.dat_Format  = FORMAT_DOS;
  2422.     dt.dat_StrDay  = tday;
  2423.     dt.dat_StrDate = tdate;
  2424.     dt.dat_StrTime = ttime;
  2425.     dt.dat_Flags   = flags ? DTF_SUBST : 0;
  2426.     dt.dat_Stamp   = *dss;
  2427.  
  2428.     myds = &(dt.dat_Stamp);
  2429.  
  2430.     if(  myds->ds_Days<0   || myds->ds_Days>36500 ||
  2431.          myds->ds_Minute<0 || myds->ds_Minute>1440 ||
  2432.          myds->ds_Tick<0   || myds->ds_Tick>3000 || !DateToStr(&dt) )
  2433.         strcpy(tdate,"---------"), strcpy(ttime,"--------");
  2434.  
  2435. #if 0
  2436.     ttime[8] = '\0';
  2437.     sprintf(timestr,"%-9s %-8s",tdate,ttime);
  2438. #endif
  2439.  
  2440.     for (dp=tdate; dp && *dp && (*dp==' ' || *dp=='\t'); dp++)
  2441.         ;
  2442.     for (tp=ttime; tp && *tp && (*tp==' ' || *tp=='\t'); tp++)
  2443.         ;
  2444.     sprintf(timestr,"%9.9s %8.8s",dp,tp);
  2445.  
  2446.     timestr[18] = '\0';    /* protection against bad timestamped files */
  2447.     return timestr;
  2448. }
  2449.  
  2450. /*
  2451.  * returns difference in msecs between two TIMEVALS (GMD)
  2452.  */
  2453.  
  2454. long tv_diff (struct timeval * tv1, struct timeval * tv2)
  2455. {
  2456.     long val;
  2457.  
  2458.     val = ((long) tv2->tv_secs - (long) tv1->tv_secs) * 1000L;
  2459.     val += (((long) tv2->tv_micro) - ((long) tv1->tv_micro)) / 1000L;
  2460.  
  2461.     return val;
  2462. }
  2463.  
  2464. /*
  2465.  * given a DateStamp structure , returns an updated TIMEVAL (GMD)
  2466.  */
  2467.  
  2468. void dss2tv (struct DateStamp * t1, struct timeval * tv)
  2469. {
  2470.     ULONG secs;
  2471.  
  2472.     secs = t1->ds_Days * 24 * 60 * 60;
  2473.     secs += t1->ds_Minute * 60;
  2474.     secs += t1->ds_Tick / TICKS_PER_SECOND;
  2475.  
  2476.     tv->tv_secs = secs;
  2477.     tv->tv_micro = (t1->ds_Tick % TICKS_PER_SECOND) * (1000000 / TICKS_PER_SECOND);
  2478. }
  2479.  
  2480. /*
  2481.  * tv2dss ; converts a timeval structure to a DateStamp structure (GMD)
  2482.  */
  2483.  
  2484. void tv2dss (struct timeval * tv, struct DateStamp * dss)
  2485. {
  2486.     long rem;
  2487.  
  2488.     dss->ds_Days = tv->tv_secs / (24 * 60 * 60);
  2489.     rem = tv->tv_secs % (24 * 60 * 60);    /* secs in last day */
  2490.  
  2491.     dss->ds_Minute = rem / 60;
  2492.     rem = rem % 60;        /* secs in last minute */
  2493.  
  2494.     rem = (rem * 1000) + (tv->tv_micro / 1000);    /* msecs in last minute */
  2495.  
  2496.     dss->ds_Tick = rem / (1000 / TICKS_PER_SECOND);    /* ticks in last minute */
  2497. }
  2498.  
  2499. /* code for battery-clock by Gary Duncan (GMD) */
  2500.  
  2501. int
  2502. do_date (void)
  2503. {
  2504.     static struct DateStamp dss_s; /* set by -s option */
  2505.     static struct timeval tv;
  2506.     struct DateStamp dss;
  2507.     struct DateTime dt;
  2508.     int i = 1;
  2509.  
  2510.     dt.dat_Format = FORMAT_DOS;
  2511.     if (ac == 1) {
  2512.         DateStamp(&dss);
  2513.         if (options & 4) {  /* its read-battery-clock time; GMD */
  2514.             struct timeval tv_batt;
  2515.             if (BattClockBase==NULL) {
  2516.                 fprintf(stderr,"No Battery Clock\n");
  2517.                 return 0;
  2518.             }
  2519.             tv_batt.tv_micro = 0;
  2520.             tv_batt.tv_secs  = ReadBattClock();
  2521.             tv2dss(&tv_batt,&dss);
  2522.         }
  2523.  
  2524.         if (options & 1) {        /* -s option */
  2525.             dss_s = dss;
  2526.             dss2tv(&dss_s,&tv);
  2527.         }
  2528.         else if (options & 2) {        /* -r option */
  2529.             long diff;
  2530.             struct timeval tv1;
  2531.  
  2532.             /*
  2533.              *  if -s not previous done , silently ignore
  2534.              */
  2535.             if (dss_s.ds_Days == 0)
  2536.                 return 0;
  2537.  
  2538.             dss2tv(&dss, &tv1);        /* current time */
  2539.             diff = tv_diff(&tv,&tv1);    /* diff in msecs */
  2540.  
  2541.             printf ("%d.%02d\n", diff / 1000, diff % 1000);
  2542.         }
  2543.         else
  2544.             printf ("%s %s\n", tday, dates (&dss, 0));
  2545.     }
  2546.     else {
  2547.         /* set the time here  */
  2548.         DateStamp (&dt.dat_Stamp);
  2549.         for (; i < ac; i++) {
  2550.             dt.dat_StrDate = NULL;
  2551.             dt.dat_StrTime = NULL;
  2552.             dt.dat_Flags = DTF_FUTURE;
  2553.             if (index (av[i], ':'))
  2554.                 dt.dat_StrTime = av[i];
  2555.             else
  2556.                 dt.dat_StrDate = av[i];
  2557.             if (!StrToDate (&dt))
  2558.                 ierror (av[i], 500);
  2559.         }
  2560.         setsystemtime (&(dt.dat_Stamp));
  2561.     }
  2562.     return 0;
  2563. }
  2564.  
  2565.